]> git.graph-it.com Git - graphit/controlpi.git/commitdiff
Update API documentation. v0.3.9
authorBenjamin Braatz <bb@bbraatz.eu>
Mon, 9 Mar 2026 10:52:55 +0000 (11:52 +0100)
committerBenjamin Braatz <bb@bbraatz.eu>
Mon, 9 Mar 2026 10:52:55 +0000 (11:52 +0100)
20 files changed:
doc/api/controlpi.html [new file with mode: 0644]
doc/api/controlpi/baseplugin.html [new file with mode: 0644]
doc/api/controlpi/messagebus.html [new file with mode: 0644]
doc/api/controlpi/pluginregistry.html [new file with mode: 0644]
doc/api/controlpi_plugins.html [new file with mode: 0644]
doc/api/controlpi_plugins/state.html [new file with mode: 0644]
doc/api/controlpi_plugins/util.html [new file with mode: 0644]
doc/api/controlpi_plugins/wait.html [new file with mode: 0644]
doc/api/index.html [new file with mode: 0644]
doc/api/search.js [new file with mode: 0644]
doc/controlpi/baseplugin.html [deleted file]
doc/controlpi/index.html [deleted file]
doc/controlpi/messagebus.html [deleted file]
doc/controlpi/pluginregistry.html [deleted file]
doc/controlpi_plugins/index.html [deleted file]
doc/controlpi_plugins/state.html [deleted file]
doc/controlpi_plugins/util.html [deleted file]
doc/controlpi_plugins/wait.html [deleted file]
doc/index.md
setup.py

diff --git a/doc/api/controlpi.html b/doc/api/controlpi.html
new file mode 100644 (file)
index 0000000..855274c
--- /dev/null
@@ -0,0 +1,704 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="index.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;
+                Module Index
+            </a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+            <h2>Submodules</h2>
+            <ul>
+                    <li><a href="controlpi/baseplugin.html">baseplugin</a></li>
+                    <li><a href="controlpi/messagebus.html">messagebus</a></li>
+                    <li><a href="controlpi/pluginregistry.html">pluginregistry</a></li>
+            </ul>
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="variable" href="#CONF_SCHEMA">CONF_SCHEMA</a>
+            </li>
+            <li>
+                    <a class="function" href="#run">run</a>
+            </li>
+            <li>
+                    <a class="function" href="#test">test</a>
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+controlpi    </h1>
+
+                        <div class="docstring"><p>Provide the infrastructure for the ControlPi system.</p>
+
+<p>The infrastructure consists of the message bus from module messagebus, the
+plugin registry from module pluginregistry and the abstract base plugin from
+module baseplugin.</p>
+
+<p>The package combines them in its run function, which is used by __main__.py
+to run a ControlPi system based on a configuration file indefinitely.</p>
+
+<p>The test function is a utility function to test plugins with minimal
+boilerplate code.</p>
+</div>
+
+                        <input id="mod-controlpi-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-controlpi-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">  1</span></a><span class="sd">&quot;&quot;&quot;Provide the infrastructure for the ControlPi system.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">  2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">  3</span></a><span class="sd">The infrastructure consists of the message bus from module messagebus, the</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">  4</span></a><span class="sd">plugin registry from module pluginregistry and the abstract base plugin from</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">  5</span></a><span class="sd">module baseplugin.</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">  6</span></a>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">  7</span></a><span class="sd">The package combines them in its run function, which is used by __main__.py</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">  8</span></a><span class="sd">to run a ControlPi system based on a configuration file indefinitely.</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">  9</span></a>
+</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="sd">The test function is a utility function to test plugins with minimal</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="sd">boilerplate code.</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a>
+</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">fastjsonschema</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a>
+</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi.messagebus</span><span class="w"> </span><span class="kn">import</span> <span class="n">MessageBus</span><span class="p">,</span> <span class="n">Message</span><span class="p">,</span> <span class="n">MessageTemplate</span>
+</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi.pluginregistry</span><span class="w"> </span><span class="kn">import</span> <span class="n">PluginRegistry</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi.baseplugin</span><span class="w"> </span><span class="kn">import</span> <span class="n">BasePlugin</span><span class="p">,</span> <span class="n">PluginConf</span><span class="p">,</span> <span class="n">ConfException</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a>
+</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Coroutine</span><span class="p">,</span> <span class="n">Any</span>
+</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a>
+</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a>
+</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a><span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">,</span> <span class="s2">&quot;patternProperties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;.*&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}}}</span>
+</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a>
+</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a>
+</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="k">def</span><span class="w"> </span><span class="nf">_process_conf</span><span class="p">(</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a>    <span class="n">message_bus</span><span class="p">:</span> <span class="n">MessageBus</span><span class="p">,</span> <span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">PluginConf</span><span class="p">]</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Coroutine</span><span class="p">]:</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a>    <span class="k">try</span><span class="p">:</span>
+</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a>        <span class="n">conf</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">validate</span><span class="p">(</span><span class="n">CONF_SCHEMA</span><span class="p">,</span> <span class="n">conf</span><span class="p">)</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a>    <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Configuration not valid:</span><span class="se">\n</span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a>        <span class="k">return</span> <span class="p">[]</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a>    <span class="n">plugins</span> <span class="o">=</span> <span class="n">PluginRegistry</span><span class="p">(</span><span class="s2">&quot;controlpi_plugins&quot;</span><span class="p">,</span> <span class="n">BasePlugin</span><span class="p">)</span>
+</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a>    <span class="n">coroutines</span> <span class="o">=</span> <span class="p">[</span><span class="n">message_bus</span><span class="o">.</span><span class="n">run</span><span class="p">()]</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a>    <span class="k">for</span> <span class="n">instance_name</span> <span class="ow">in</span> <span class="n">conf</span><span class="p">:</span>
+</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a>        <span class="n">instance_conf</span> <span class="o">=</span> <span class="n">conf</span><span class="p">[</span><span class="n">instance_name</span><span class="p">]</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a>        <span class="k">if</span> <span class="s2">&quot;plugin&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">instance_conf</span><span class="p">:</span>
+</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a>            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No plugin implementation specified for instance &#39;</span><span class="si">{</span><span class="n">instance_name</span><span class="si">}</span><span class="s2">&#39;.&quot;</span><span class="p">)</span>
+</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a>            <span class="k">continue</span>
+</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a>        <span class="n">plugin_name</span> <span class="o">=</span> <span class="n">instance_conf</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span>
+</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a>        <span class="k">if</span> <span class="n">plugin_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">plugins</span><span class="p">:</span>
+</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a>            <span class="nb">print</span><span class="p">(</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a>                <span class="sa">f</span><span class="s2">&quot;No implementation found for plugin &#39;</span><span class="si">{</span><span class="n">plugin_name</span><span class="si">}</span><span class="s2">&#39;&quot;</span>
+</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a>                <span class="sa">f</span><span class="s2">&quot; (specified for instance &#39;</span><span class="si">{</span><span class="n">instance_name</span><span class="si">}</span><span class="s2">&#39;).&quot;</span>
+</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a>            <span class="p">)</span>
+</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a>            <span class="k">continue</span>
+</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a>        <span class="n">plugin</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">[</span><span class="n">plugin_name</span><span class="p">]</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a>        <span class="k">try</span><span class="p">:</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a>            <span class="n">instance</span> <span class="o">=</span> <span class="n">plugin</span><span class="p">(</span><span class="n">message_bus</span><span class="p">,</span> <span class="n">instance_name</span><span class="p">,</span> <span class="n">instance_conf</span><span class="p">)</span>
+</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a>            <span class="n">coroutines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">instance</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a>        <span class="k">except</span> <span class="n">ConfException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a>            <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a>            <span class="k">continue</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a>    <span class="k">return</span> <span class="n">coroutines</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a>
+</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a>
+</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">PluginConf</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Run the ControlPi system based on a configuration.</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a>
+</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="sd">    Setup message bus, process given configuration, and run message bus and</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="sd">    plugins concurrently and indefinitely.</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a>
+</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="sd">    This function is mainly used by __main__.py to run a ControlPi system</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="sd">    based on a configuration loaded from a configuration JSON file on disk.</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a>
+</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="sd">    &gt;&gt;&gt; async def test_coroutine():</span>
+</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a><span class="sd">    ...     conf = {&quot;Example Init&quot;:</span>
+</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a><span class="sd">    ...             {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="sd">    ...              &quot;messages&quot;: [{&quot;id&quot;: 42,</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a><span class="sd">    ...                            &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd">    ...                           {&quot;id&quot;: 42.42,</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="sd">    ...                            &quot;content&quot;: &quot;Second Message&quot;}]},</span>
+</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd">    ...             &quot;Example Log&quot;:</span>
+</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a><span class="sd">    ...             {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd">    ...              &quot;filter&quot;: [{&quot;sender&quot;: {&quot;const&quot;: &quot;Example Init&quot;}}]}}</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd">    ...     run_task = asyncio.create_task(run(conf))</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd">    ...     await asyncio.sleep(0.1)</span>
+</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd">    ...     run_task.cancel()</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd">    ...     try:</span>
+</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd">    ...         await run_task</span>
+</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="sd">    ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a><span class="sd">    ...         pass</span>
+</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test_coroutine())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a><span class="sd">    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a><span class="sd">                  &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a><span class="sd">    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a><span class="sd">                  &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a>    <span class="n">message_bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>    <span class="n">coroutines</span> <span class="o">=</span> <span class="n">_process_conf</span><span class="p">(</span><span class="n">message_bus</span><span class="p">,</span> <span class="n">conf</span><span class="p">)</span>
+</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a>    <span class="k">try</span><span class="p">:</span>
+</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="o">*</span><span class="n">coroutines</span><span class="p">)</span>
+</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a>        <span class="k">pass</span>
+</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a>
+</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a>
+</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test</span><span class="p">(</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a>    <span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">PluginConf</span><span class="p">],</span> <span class="n">messages</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]],</span> <span class="n">wait</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Test configuration of ControlPi system.</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a>
+</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a><span class="sd">    Setup message bus, process given configuration, run message bus and</span>
+</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="sd">    plugins concurrently, send given messages on message bus and print all</span>
+</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a><span class="sd">    messages on message bus. Terminate when queue of message bus is empty.</span>
+</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a>
+</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a><span class="sd">    This function allows to test single plugins or small plugin</span>
+</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="sd">    configurations with minimal boilerplate code:</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test(</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a><span class="sd">    ...     {&quot;Example Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="sd">    ...                       &quot;messages&quot;: [{&quot;id&quot;: 42,</span>
+</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="sd">    ...                                     &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="sd">    ...                                    {&quot;id&quot;: 42.42,</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="sd">    ...                                     &quot;content&quot;: &quot;Second Message&quot;}]}},</span>
+</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Example Init&quot;,</span>
+</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="sd">    ...       &quot;command&quot;: &quot;execute&quot;}]))  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a><span class="sd">             &#39;client&#39;: &#39;Example Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>
+</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd">                       {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>
+</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Example Init&#39;},</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd">             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd">             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd">             &#39;command&#39;: &#39;execute&#39;}</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a><span class="sd">             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a><span class="sd">             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a>
+</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a><span class="sd">    Similar functionality could be reached by using the Log and Init plugins</span>
+</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a><span class="sd">    to print messages and send some messages on the bus, but these would</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a><span class="sd">    clutter the test configuration and code to stop the indefinitely running</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a><span class="sd">    bus would have to be added to each and every test.</span>
+</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a>
+</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a><span class="sd">    Incorrect plugin configurations can also be tested by this:</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test(</span>
+</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a><span class="sd">    ...     {&quot;Example Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;}}, []))</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a><span class="sd">    data must contain [&#39;messages&#39;] properties</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a><span class="sd">    Configuration for &#39;Example Init&#39; is not valid.</span>
+</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a>    <span class="n">message_bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a>
+</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">log</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a>        <span class="k">if</span> <span class="p">(</span>
+</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a>            <span class="s2">&quot;sender&quot;</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a>            <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a>            <span class="ow">and</span> <span class="s2">&quot;event&quot;</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a>            <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;registered&quot;</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a>            <span class="ow">and</span> <span class="s2">&quot;client&quot;</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a>            <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;test()&quot;</span>
+</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a>        <span class="p">):</span>
+</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a>            <span class="c1"># Do not log own registration of &#39;test()&#39;:</span>
+</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a>            <span class="k">return</span>
+</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;test(): </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a>
+</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a>    <span class="n">message_bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a>        <span class="s2">&quot;test()&quot;</span><span class="p">,</span> <span class="s2">&quot;Test&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">()],</span> <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">()],</span> <span class="n">log</span><span class="p">)]</span>
+</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a>    <span class="p">)</span>
+</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a>
+</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a>    <span class="n">coroutines</span> <span class="o">=</span> <span class="n">_process_conf</span><span class="p">(</span><span class="n">message_bus</span><span class="p">,</span> <span class="n">conf</span><span class="p">)</span>
+</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a>    <span class="n">background_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a>    <span class="k">for</span> <span class="n">coroutine</span> <span class="ow">in</span> <span class="n">coroutines</span><span class="p">:</span>
+</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">coroutine</span><span class="p">)</span>
+</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a>        <span class="n">background_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="n">background_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a>        <span class="c1"># Give the created task opportunity to run:</span>
+</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a>    <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">:</span>
+</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a>        <span class="k">await</span> <span class="n">message_bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;test()&quot;</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a>        <span class="c1"># Give immediate reactions to messages opportunity to happen:</span>
+</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">wait</span><span class="p">)</span>
+</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a>    <span class="k">await</span> <span class="n">message_bus</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="CONF_SCHEMA">
+                    <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;type&#39;: &#39;object&#39;, &#39;patternProperties&#39;: {&#39;.*&#39;: {&#39;type&#39;: &#39;object&#39;}}}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#CONF_SCHEMA"></a>
+    
+    
+
+                </section>
+                <section id="run">
+                            <input id="run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="run-60"><a href="#run-60"><span class="linenos">60</span></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">PluginConf</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="run-61"><a href="#run-61"><span class="linenos">61</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Run the ControlPi system based on a configuration.</span>
+</span><span id="run-62"><a href="#run-62"><span class="linenos">62</span></a>
+</span><span id="run-63"><a href="#run-63"><span class="linenos">63</span></a><span class="sd">    Setup message bus, process given configuration, and run message bus and</span>
+</span><span id="run-64"><a href="#run-64"><span class="linenos">64</span></a><span class="sd">    plugins concurrently and indefinitely.</span>
+</span><span id="run-65"><a href="#run-65"><span class="linenos">65</span></a>
+</span><span id="run-66"><a href="#run-66"><span class="linenos">66</span></a><span class="sd">    This function is mainly used by __main__.py to run a ControlPi system</span>
+</span><span id="run-67"><a href="#run-67"><span class="linenos">67</span></a><span class="sd">    based on a configuration loaded from a configuration JSON file on disk.</span>
+</span><span id="run-68"><a href="#run-68"><span class="linenos">68</span></a>
+</span><span id="run-69"><a href="#run-69"><span class="linenos">69</span></a><span class="sd">    &gt;&gt;&gt; async def test_coroutine():</span>
+</span><span id="run-70"><a href="#run-70"><span class="linenos">70</span></a><span class="sd">    ...     conf = {&quot;Example Init&quot;:</span>
+</span><span id="run-71"><a href="#run-71"><span class="linenos">71</span></a><span class="sd">    ...             {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="run-72"><a href="#run-72"><span class="linenos">72</span></a><span class="sd">    ...              &quot;messages&quot;: [{&quot;id&quot;: 42,</span>
+</span><span id="run-73"><a href="#run-73"><span class="linenos">73</span></a><span class="sd">    ...                            &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="run-74"><a href="#run-74"><span class="linenos">74</span></a><span class="sd">    ...                           {&quot;id&quot;: 42.42,</span>
+</span><span id="run-75"><a href="#run-75"><span class="linenos">75</span></a><span class="sd">    ...                            &quot;content&quot;: &quot;Second Message&quot;}]},</span>
+</span><span id="run-76"><a href="#run-76"><span class="linenos">76</span></a><span class="sd">    ...             &quot;Example Log&quot;:</span>
+</span><span id="run-77"><a href="#run-77"><span class="linenos">77</span></a><span class="sd">    ...             {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="run-78"><a href="#run-78"><span class="linenos">78</span></a><span class="sd">    ...              &quot;filter&quot;: [{&quot;sender&quot;: {&quot;const&quot;: &quot;Example Init&quot;}}]}}</span>
+</span><span id="run-79"><a href="#run-79"><span class="linenos">79</span></a><span class="sd">    ...     run_task = asyncio.create_task(run(conf))</span>
+</span><span id="run-80"><a href="#run-80"><span class="linenos">80</span></a><span class="sd">    ...     await asyncio.sleep(0.1)</span>
+</span><span id="run-81"><a href="#run-81"><span class="linenos">81</span></a><span class="sd">    ...     run_task.cancel()</span>
+</span><span id="run-82"><a href="#run-82"><span class="linenos">82</span></a><span class="sd">    ...     try:</span>
+</span><span id="run-83"><a href="#run-83"><span class="linenos">83</span></a><span class="sd">    ...         await run_task</span>
+</span><span id="run-84"><a href="#run-84"><span class="linenos">84</span></a><span class="sd">    ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="run-85"><a href="#run-85"><span class="linenos">85</span></a><span class="sd">    ...         pass</span>
+</span><span id="run-86"><a href="#run-86"><span class="linenos">86</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test_coroutine())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="run-87"><a href="#run-87"><span class="linenos">87</span></a><span class="sd">    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="run-88"><a href="#run-88"><span class="linenos">88</span></a><span class="sd">                  &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="run-89"><a href="#run-89"><span class="linenos">89</span></a><span class="sd">    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="run-90"><a href="#run-90"><span class="linenos">90</span></a><span class="sd">                  &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="run-91"><a href="#run-91"><span class="linenos">91</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="run-92"><a href="#run-92"><span class="linenos">92</span></a>    <span class="n">message_bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+</span><span id="run-93"><a href="#run-93"><span class="linenos">93</span></a>    <span class="n">coroutines</span> <span class="o">=</span> <span class="n">_process_conf</span><span class="p">(</span><span class="n">message_bus</span><span class="p">,</span> <span class="n">conf</span><span class="p">)</span>
+</span><span id="run-94"><a href="#run-94"><span class="linenos">94</span></a>    <span class="k">try</span><span class="p">:</span>
+</span><span id="run-95"><a href="#run-95"><span class="linenos">95</span></a>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="o">*</span><span class="n">coroutines</span><span class="p">)</span>
+</span><span id="run-96"><a href="#run-96"><span class="linenos">96</span></a>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+</span><span id="run-97"><a href="#run-97"><span class="linenos">97</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run the ControlPi system based on a configuration.</p>
+
+<p>Setup message bus, process given configuration, and run message bus and
+plugins concurrently and indefinitely.</p>
+
+<p>This function is mainly used by __main__.py to run a ControlPi system
+based on a configuration loaded from a configuration JSON file on disk.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test_coroutine</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">conf</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;Example Init&quot;</span><span class="p">:</span>
+<span class="gp">... </span>            <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+<span class="gp">... </span>             <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span>
+<span class="gp">... </span>                           <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">},</span>
+<span class="gp">... </span>                          <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">,</span>
+<span class="gp">... </span>                           <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Second Message&quot;</span><span class="p">}]},</span>
+<span class="gp">... </span>            <span class="s2">&quot;Example Log&quot;</span><span class="p">:</span>
+<span class="gp">... </span>            <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span>
+<span class="gp">... </span>             <span class="s2">&quot;filter&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;Example Init&quot;</span><span class="p">}}]}}</span>
+<span class="gp">... </span>    <span class="n">run_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">run</span><span class="p">(</span><span class="n">conf</span><span class="p">))</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">run_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">run_task</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test_coroutine</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+<span class="go">              &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+<span class="go">              &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                </section>
+                <section id="test">
+                            <input id="test-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">test</span><span class="signature pdoc-code multiline">(<span class="param">        <span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span>,</span><span class="param">       <span class="n">messages</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span>,</span><span class="param">       <span class="n">wait</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="test-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#test"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="test-100"><a href="#test-100"><span class="linenos">100</span></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test</span><span class="p">(</span>
+</span><span id="test-101"><a href="#test-101"><span class="linenos">101</span></a>    <span class="n">conf</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">PluginConf</span><span class="p">],</span> <span class="n">messages</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]],</span> <span class="n">wait</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span>
+</span><span id="test-102"><a href="#test-102"><span class="linenos">102</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="test-103"><a href="#test-103"><span class="linenos">103</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Test configuration of ControlPi system.</span>
+</span><span id="test-104"><a href="#test-104"><span class="linenos">104</span></a>
+</span><span id="test-105"><a href="#test-105"><span class="linenos">105</span></a><span class="sd">    Setup message bus, process given configuration, run message bus and</span>
+</span><span id="test-106"><a href="#test-106"><span class="linenos">106</span></a><span class="sd">    plugins concurrently, send given messages on message bus and print all</span>
+</span><span id="test-107"><a href="#test-107"><span class="linenos">107</span></a><span class="sd">    messages on message bus. Terminate when queue of message bus is empty.</span>
+</span><span id="test-108"><a href="#test-108"><span class="linenos">108</span></a>
+</span><span id="test-109"><a href="#test-109"><span class="linenos">109</span></a><span class="sd">    This function allows to test single plugins or small plugin</span>
+</span><span id="test-110"><a href="#test-110"><span class="linenos">110</span></a><span class="sd">    configurations with minimal boilerplate code:</span>
+</span><span id="test-111"><a href="#test-111"><span class="linenos">111</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test(</span>
+</span><span id="test-112"><a href="#test-112"><span class="linenos">112</span></a><span class="sd">    ...     {&quot;Example Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="test-113"><a href="#test-113"><span class="linenos">113</span></a><span class="sd">    ...                       &quot;messages&quot;: [{&quot;id&quot;: 42,</span>
+</span><span id="test-114"><a href="#test-114"><span class="linenos">114</span></a><span class="sd">    ...                                     &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="test-115"><a href="#test-115"><span class="linenos">115</span></a><span class="sd">    ...                                    {&quot;id&quot;: 42.42,</span>
+</span><span id="test-116"><a href="#test-116"><span class="linenos">116</span></a><span class="sd">    ...                                     &quot;content&quot;: &quot;Second Message&quot;}]}},</span>
+</span><span id="test-117"><a href="#test-117"><span class="linenos">117</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Example Init&quot;,</span>
+</span><span id="test-118"><a href="#test-118"><span class="linenos">118</span></a><span class="sd">    ...       &quot;command&quot;: &quot;execute&quot;}]))  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="test-119"><a href="#test-119"><span class="linenos">119</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="test-120"><a href="#test-120"><span class="linenos">120</span></a><span class="sd">             &#39;client&#39;: &#39;Example Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+</span><span id="test-121"><a href="#test-121"><span class="linenos">121</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="test-122"><a href="#test-122"><span class="linenos">122</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>
+</span><span id="test-123"><a href="#test-123"><span class="linenos">123</span></a><span class="sd">                       {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>
+</span><span id="test-124"><a href="#test-124"><span class="linenos">124</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>
+</span><span id="test-125"><a href="#test-125"><span class="linenos">125</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Example Init&#39;},</span>
+</span><span id="test-126"><a href="#test-126"><span class="linenos">126</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="test-127"><a href="#test-127"><span class="linenos">127</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="test-128"><a href="#test-128"><span class="linenos">128</span></a><span class="sd">             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="test-129"><a href="#test-129"><span class="linenos">129</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="test-130"><a href="#test-130"><span class="linenos">130</span></a><span class="sd">             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="test-131"><a href="#test-131"><span class="linenos">131</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Example Init&#39;,</span>
+</span><span id="test-132"><a href="#test-132"><span class="linenos">132</span></a><span class="sd">             &#39;command&#39;: &#39;execute&#39;}</span>
+</span><span id="test-133"><a href="#test-133"><span class="linenos">133</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="test-134"><a href="#test-134"><span class="linenos">134</span></a><span class="sd">             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="test-135"><a href="#test-135"><span class="linenos">135</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+</span><span id="test-136"><a href="#test-136"><span class="linenos">136</span></a><span class="sd">             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="test-137"><a href="#test-137"><span class="linenos">137</span></a>
+</span><span id="test-138"><a href="#test-138"><span class="linenos">138</span></a><span class="sd">    Similar functionality could be reached by using the Log and Init plugins</span>
+</span><span id="test-139"><a href="#test-139"><span class="linenos">139</span></a><span class="sd">    to print messages and send some messages on the bus, but these would</span>
+</span><span id="test-140"><a href="#test-140"><span class="linenos">140</span></a><span class="sd">    clutter the test configuration and code to stop the indefinitely running</span>
+</span><span id="test-141"><a href="#test-141"><span class="linenos">141</span></a><span class="sd">    bus would have to be added to each and every test.</span>
+</span><span id="test-142"><a href="#test-142"><span class="linenos">142</span></a>
+</span><span id="test-143"><a href="#test-143"><span class="linenos">143</span></a><span class="sd">    Incorrect plugin configurations can also be tested by this:</span>
+</span><span id="test-144"><a href="#test-144"><span class="linenos">144</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test(</span>
+</span><span id="test-145"><a href="#test-145"><span class="linenos">145</span></a><span class="sd">    ...     {&quot;Example Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;}}, []))</span>
+</span><span id="test-146"><a href="#test-146"><span class="linenos">146</span></a><span class="sd">    data must contain [&#39;messages&#39;] properties</span>
+</span><span id="test-147"><a href="#test-147"><span class="linenos">147</span></a><span class="sd">    Configuration for &#39;Example Init&#39; is not valid.</span>
+</span><span id="test-148"><a href="#test-148"><span class="linenos">148</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="test-149"><a href="#test-149"><span class="linenos">149</span></a>    <span class="n">message_bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+</span><span id="test-150"><a href="#test-150"><span class="linenos">150</span></a>
+</span><span id="test-151"><a href="#test-151"><span class="linenos">151</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">log</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="test-152"><a href="#test-152"><span class="linenos">152</span></a>        <span class="k">if</span> <span class="p">(</span>
+</span><span id="test-153"><a href="#test-153"><span class="linenos">153</span></a>            <span class="s2">&quot;sender&quot;</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="test-154"><a href="#test-154"><span class="linenos">154</span></a>            <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span>
+</span><span id="test-155"><a href="#test-155"><span class="linenos">155</span></a>            <span class="ow">and</span> <span class="s2">&quot;event&quot;</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="test-156"><a href="#test-156"><span class="linenos">156</span></a>            <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;registered&quot;</span>
+</span><span id="test-157"><a href="#test-157"><span class="linenos">157</span></a>            <span class="ow">and</span> <span class="s2">&quot;client&quot;</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="test-158"><a href="#test-158"><span class="linenos">158</span></a>            <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;test()&quot;</span>
+</span><span id="test-159"><a href="#test-159"><span class="linenos">159</span></a>        <span class="p">):</span>
+</span><span id="test-160"><a href="#test-160"><span class="linenos">160</span></a>            <span class="c1"># Do not log own registration of &#39;test()&#39;:</span>
+</span><span id="test-161"><a href="#test-161"><span class="linenos">161</span></a>            <span class="k">return</span>
+</span><span id="test-162"><a href="#test-162"><span class="linenos">162</span></a>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;test(): </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="test-163"><a href="#test-163"><span class="linenos">163</span></a>
+</span><span id="test-164"><a href="#test-164"><span class="linenos">164</span></a>    <span class="n">message_bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="test-165"><a href="#test-165"><span class="linenos">165</span></a>        <span class="s2">&quot;test()&quot;</span><span class="p">,</span> <span class="s2">&quot;Test&quot;</span><span class="p">,</span> <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">()],</span> <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">()],</span> <span class="n">log</span><span class="p">)]</span>
+</span><span id="test-166"><a href="#test-166"><span class="linenos">166</span></a>    <span class="p">)</span>
+</span><span id="test-167"><a href="#test-167"><span class="linenos">167</span></a>
+</span><span id="test-168"><a href="#test-168"><span class="linenos">168</span></a>    <span class="n">coroutines</span> <span class="o">=</span> <span class="n">_process_conf</span><span class="p">(</span><span class="n">message_bus</span><span class="p">,</span> <span class="n">conf</span><span class="p">)</span>
+</span><span id="test-169"><a href="#test-169"><span class="linenos">169</span></a>    <span class="n">background_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="test-170"><a href="#test-170"><span class="linenos">170</span></a>    <span class="k">for</span> <span class="n">coroutine</span> <span class="ow">in</span> <span class="n">coroutines</span><span class="p">:</span>
+</span><span id="test-171"><a href="#test-171"><span class="linenos">171</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">coroutine</span><span class="p">)</span>
+</span><span id="test-172"><a href="#test-172"><span class="linenos">172</span></a>        <span class="n">background_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="test-173"><a href="#test-173"><span class="linenos">173</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="n">background_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="test-174"><a href="#test-174"><span class="linenos">174</span></a>        <span class="c1"># Give the created task opportunity to run:</span>
+</span><span id="test-175"><a href="#test-175"><span class="linenos">175</span></a>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="test-176"><a href="#test-176"><span class="linenos">176</span></a>    <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">:</span>
+</span><span id="test-177"><a href="#test-177"><span class="linenos">177</span></a>        <span class="k">await</span> <span class="n">message_bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;test()&quot;</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="test-178"><a href="#test-178"><span class="linenos">178</span></a>        <span class="c1"># Give immediate reactions to messages opportunity to happen:</span>
+</span><span id="test-179"><a href="#test-179"><span class="linenos">179</span></a>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="test-180"><a href="#test-180"><span class="linenos">180</span></a>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">wait</span><span class="p">)</span>
+</span><span id="test-181"><a href="#test-181"><span class="linenos">181</span></a>    <span class="k">await</span> <span class="n">message_bus</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Test configuration of ControlPi system.</p>
+
+<p>Setup message bus, process given configuration, run message bus and
+plugins concurrently, send given messages on message bus and print all
+messages on message bus. Terminate when queue of message bus is empty.</p>
+
+<p>This function allows to test single plugins or small plugin
+configurations with minimal boilerplate code:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test</span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Example Init&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                      <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span>
+<span class="gp">... </span>                                    <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">},</span>
+<span class="gp">... </span>                                   <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">,</span>
+<span class="gp">... </span>                                    <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Second Message&quot;</span><span class="p">}]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Example Init&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">}]))</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Example Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+<span class="go">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>
+<span class="go">                   {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>
+<span class="go">                    &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Example Init&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+<span class="go">         &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+<span class="go">         &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Example Init&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;execute&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+<span class="go">         &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>
+<span class="go">         &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</code></pre>
+</div>
+
+<p>Similar functionality could be reached by using the Log and Init plugins
+to print messages and send some messages on the bus, but these would
+clutter the test configuration and code to stop the indefinitely running
+bus would have to be added to each and every test.</p>
+
+<p>Incorrect plugin configurations can also be tested by this:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test</span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Example Init&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">}},</span> <span class="p">[]))</span>
+<span class="go">data must contain [&#39;messages&#39;] properties</span>
+<span class="go">Configuration for &#39;Example Init&#39; is not valid.</span>
+</code></pre>
+</div>
+</div>
+
+
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi/baseplugin.html b/doc/api/controlpi/baseplugin.html
new file mode 100644 (file)
index 0000000..6089efd
--- /dev/null
@@ -0,0 +1,933 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi.baseplugin API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="../controlpi.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;controlpi</a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="variable" href="#JSONSchema">JSONSchema</a>
+            </li>
+            <li>
+                    <a class="variable" href="#PluginConf">PluginConf</a>
+            </li>
+            <li>
+                    <a class="class" href="#ConfException">ConfException</a>
+                            <ul class="memberlist">
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#BasePlugin">BasePlugin</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#BasePlugin.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="variable" href="#BasePlugin.bus">bus</a>
+                        </li>
+                        <li>
+                                <a class="variable" href="#BasePlugin.name">name</a>
+                        </li>
+                        <li>
+                                <a class="variable" href="#BasePlugin.conf">conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#BasePlugin.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#BasePlugin.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+<a href="./../controlpi.html">controlpi</a><wbr>.baseplugin    </h1>
+
+                        <div class="docstring"><p>Define base class for all ControlPi plugins.</p>
+
+<p>The class BasePlugin provides the abstract base class for concrete plugins
+running on the ControlPi system.</p>
+
+<p>It has three abstract methods that have to be implemented by all concrete
+plugins:</p>
+
+<ul>
+<li>The class property CONF_SCHEMA is the JSON schema of the configuration of
+the plugin. The configuration read from the global configuration file is
+checked against this schema during initialisation.</li>
+<li>The method process_conf is called at the end of initialisation and is used
+to initialise the plugin. It can be assumed that self.bus is the message
+bus of the system, self.name the instance name, and self.conf the
+configuration already validated against the schema.</li>
+<li>The run coroutines of all plugins are executed concurrently by the main
+system.</li>
+</ul>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">TestPlugin</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span>
+<span class="gp">... </span>                   <span class="s1">&#39;required&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]}</span>
+<span class="gp">... </span>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="k">if</span> <span class="s1">&#39;key&#39;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+<span class="gp">... </span>            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing &#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&#39;.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Doing something else.&quot;</span><span class="p">)</span>
+</code></pre>
+</div>
+
+<p>Plugins are configured and run based on the information in the global
+configuration. Here, we test this manually:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">p</span> <span class="o">=</span> <span class="n">TestPlugin</span><span class="p">(</span><span class="n">MessageBus</span><span class="p">(),</span> <span class="s1">&#39;Test Instance&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;Something&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">p</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test</span><span class="p">())</span>
+<span class="go">Processing &#39;Something&#39;.</span>
+<span class="go">Doing something else.</span>
+</code></pre>
+</div>
+
+<p>Each plugin gets a reference to the system message bus during
+initialisation, which can be accessed as self.bus in the functions of the
+plugin class. This can be used to register and unregister message bus
+clients:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">BusPlugin</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="gp">... </span>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">&#39;BusPlugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                          <span class="p">[{</span><span class="s1">&#39;event&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}}],</span>
+<span class="gp">... </span>                          <span class="p">[([{</span><span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">}}],</span>
+<span class="gp">... </span>                            <span class="bp">self</span><span class="o">.</span><span class="n">_receive</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_receive</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> received </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">&#39;event&#39;</span><span class="p">:</span> <span class="s1">&#39;Receive&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">&#39;event&#39;</span><span class="p">:</span> <span class="s1">&#39;Run&#39;</span><span class="p">})</span>
+</code></pre>
+</div>
+
+<p>Again, we run this manually here, but this is done by the main coroutine
+when using the system in production:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">log</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Log: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test_bus_plugin</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="n">p</span> <span class="o">=</span> <span class="n">BusPlugin</span><span class="p">(</span><span class="n">bus</span><span class="p">,</span> <span class="s1">&#39;Bus Test&#39;</span><span class="p">,</span> <span class="p">{})</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Test&#39;</span><span class="p">,</span> <span class="s1">&#39;TestPlugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[{}],</span> <span class="p">[([{</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Bus Test&#39;</span><span class="p">}}],</span> <span class="n">log</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="n">plugin_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Test&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Bus Test&#39;</span><span class="p">,</span> <span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;v&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="n">bus_task</span><span class="p">,</span> <span class="n">plugin_task</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test_bus_plugin</span><span class="p">())</span>
+<span class="go">Bus Test received {&#39;sender&#39;: &#39;Test&#39;, &#39;target&#39;: &#39;Bus Test&#39;, &#39;key&#39;: &#39;v&#39;}.</span>
+<span class="go">Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Run&#39;}</span>
+<span class="go">Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Receive&#39;}</span>
+</code></pre>
+</div>
+
+<p>Often, there will be a one-to-one correspondence between plugin
+instances and message bus clients, a plugin instance will be a message bus
+client. But there are also cases, where one plugin instance might register
+and unregister a lot of message bus clients, maybe even dynamically through
+its lifetime. A plugin for an input/output card might register separate
+clients for each pin of the card, a plugin for some kind of hardware bus
+might register separate clients for all devices connected to the bus, or a
+network socket plugin might register separate clients for all connections
+to the socket (and unregister them when the connection is closed).</p>
+</div>
+
+                        <input id="mod-baseplugin-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-baseplugin-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">  1</span></a><span class="sd">&quot;&quot;&quot;Define base class for all ControlPi plugins.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">  2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">  3</span></a><span class="sd">The class BasePlugin provides the abstract base class for concrete plugins</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">  4</span></a><span class="sd">running on the ControlPi system.</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">  5</span></a>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">  6</span></a><span class="sd">It has three abstract methods that have to be implemented by all concrete</span>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">  7</span></a><span class="sd">plugins:</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">  8</span></a><span class="sd">- The class property CONF_SCHEMA is the JSON schema of the configuration of</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">  9</span></a><span class="sd">  the plugin. The configuration read from the global configuration file is</span>
+</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="sd">  checked against this schema during initialisation.</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="sd">- The method process_conf is called at the end of initialisation and is used</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a><span class="sd">  to initialise the plugin. It can be assumed that self.bus is the message</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a><span class="sd">  bus of the system, self.name the instance name, and self.conf the</span>
+</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="sd">  configuration already validated against the schema.</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a><span class="sd">- The run coroutines of all plugins are executed concurrently by the main</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="sd">  system.</span>
+</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="sd">&gt;&gt;&gt; class TestPlugin(BasePlugin):</span>
+</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="sd">...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a><span class="sd">...                    &#39;required&#39;: [&#39;key&#39;]}</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a><span class="sd">...     def process_conf(self):</span>
+</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a><span class="sd">...         if &#39;key&#39; in self.conf:</span>
+</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="sd">...             print(f&quot;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&quot;)</span>
+</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a><span class="sd">...     async def run(self):</span>
+</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a><span class="sd">...         print(&quot;Doing something else.&quot;)</span>
+</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a>
+</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a><span class="sd">Plugins are configured and run based on the information in the global</span>
+</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="sd">configuration. Here, we test this manually:</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a><span class="sd">&gt;&gt;&gt; import asyncio</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="sd">&gt;&gt;&gt; async def test():</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a><span class="sd">...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;, {&#39;key&#39;: &#39;Something&#39;})</span>
+</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="sd">...     await p.run()</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a><span class="sd">&gt;&gt;&gt; asyncio.run(test())</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a><span class="sd">Processing &#39;Something&#39;.</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a><span class="sd">Doing something else.</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a>
+</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a><span class="sd">Each plugin gets a reference to the system message bus during</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a><span class="sd">initialisation, which can be accessed as self.bus in the functions of the</span>
+</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a><span class="sd">plugin class. This can be used to register and unregister message bus</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a><span class="sd">clients:</span>
+</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a><span class="sd">&gt;&gt;&gt; class BusPlugin(BasePlugin):</span>
+</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a><span class="sd">...     CONF_SCHEMA = True</span>
+</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a><span class="sd">...     def process_conf(self):</span>
+</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a><span class="sd">...         self.bus.register(self.name, &#39;BusPlugin&#39;,</span>
+</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="sd">...                           [{&#39;event&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a><span class="sd">...                           [([{&#39;target&#39;: {&#39;const&#39;: self.name}}],</span>
+</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="sd">...                             self._receive)])</span>
+</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="sd">...     async def _receive(self, message):</span>
+</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a><span class="sd">...         print(f&quot;{self.name} received {message}.&quot;)</span>
+</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="sd">...         await self.bus.send({&#39;sender&#39;: self.name, &#39;event&#39;: &#39;Receive&#39;})</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="sd">...     async def run(self):</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a><span class="sd">...         await self.bus.send({&#39;sender&#39;: self.name, &#39;event&#39;: &#39;Run&#39;})</span>
+</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a>
+</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a><span class="sd">Again, we run this manually here, but this is done by the main coroutine</span>
+</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a><span class="sd">when using the system in production:</span>
+</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a><span class="sd">&gt;&gt;&gt; async def log(message):</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a><span class="sd">...     print(f&quot;Log: {message}&quot;)</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a><span class="sd">&gt;&gt;&gt; async def test_bus_plugin():</span>
+</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a><span class="sd">...     bus = MessageBus()</span>
+</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="sd">...     p = BusPlugin(bus, &#39;Bus Test&#39;, {})</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="sd">...     bus.register(&#39;Test&#39;, &#39;TestPlugin&#39;,</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="sd">...                  [{}], [([{&#39;sender&#39;: {&#39;const&#39;: &#39;Bus Test&#39;}}], log)])</span>
+</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="sd">...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="sd">...     plugin_task = asyncio.create_task(p.run())</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a><span class="sd">...     await bus.send({&#39;sender&#39;: &#39;Test&#39;, &#39;target&#39;: &#39;Bus Test&#39;, &#39;key&#39;: &#39;v&#39;})</span>
+</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="sd">...     await asyncio.sleep(0)</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="sd">...     await asyncio.sleep(0)</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="sd">...     bus_task.cancel()</span>
+</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="sd">...     try:</span>
+</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a><span class="sd">...         await asyncio.gather(bus_task, plugin_task)</span>
+</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a><span class="sd">...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="sd">...         pass</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a><span class="sd">&gt;&gt;&gt; asyncio.run(test_bus_plugin())</span>
+</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd">Bus Test received {&#39;sender&#39;: &#39;Test&#39;, &#39;target&#39;: &#39;Bus Test&#39;, &#39;key&#39;: &#39;v&#39;}.</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="sd">Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Run&#39;}</span>
+</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd">Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Receive&#39;}</span>
+</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a>
+</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd">Often, there will be a one-to-one correspondence between plugin</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd">instances and message bus clients, a plugin instance will be a message bus</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd">client. But there are also cases, where one plugin instance might register</span>
+</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd">and unregister a lot of message bus clients, maybe even dynamically through</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd">its lifetime. A plugin for an input/output card might register separate</span>
+</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd">clients for each pin of the card, a plugin for some kind of hardware bus</span>
+</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="sd">might register separate clients for all devices connected to the bus, or a</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a><span class="sd">network socket plugin might register separate clients for all connections</span>
+</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a><span class="sd">to the socket (and unregister them when the connection is closed).</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a>
+</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a><span class="n">__pdoc__</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;BasePlugin.CONF_SCHEMA&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">}</span>
+</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a>
+</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
+</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">fastjsonschema</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>
+</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi.messagebus</span><span class="w"> </span><span class="kn">import</span> <span class="n">MessageBus</span>
+</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a>
+</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Union</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Callable</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a>
+</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a><span class="n">JSONSchema</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span>
+</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a>    <span class="nb">bool</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Union</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]]</span>
+</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="p">]</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="c1"># Could be more specific.</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a><span class="n">PluginConf</span> <span class="o">=</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span>
+</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a><span class="c1"># Could be more specific.</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a>
+</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a>
+</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="k">class</span><span class="w"> </span><span class="nc">ConfException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Raise for errors in plugin configurations.&quot;&quot;&quot;</span>
+</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a>
+</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a>
+</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="k">class</span><span class="w"> </span><span class="nc">BasePlugin</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Base class for all ControlPi plugins.</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a>
+</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="sd">    &gt;&gt;&gt; class TestPlugin(BasePlugin):</span>
+</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="sd">    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},</span>
+</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="sd">    ...                    &#39;required&#39;: [&#39;key&#39;]}</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="sd">    ...     def process_conf(self):</span>
+</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a><span class="sd">    ...         if &#39;key&#39; in self.conf:</span>
+</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="sd">    ...             print(f&quot;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&quot;)</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="sd">    ...     async def run(self):</span>
+</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a><span class="sd">    ...         print(&quot;Doing something else.&quot;)</span>
+</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a>
+</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="sd">    Initialisation sets the instance variables bus to the given message bus,</span>
+</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd">    name to the given name, and conf to the given configuration:</span>
+</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd">    &gt;&gt;&gt; class TestPlugin(BasePlugin):</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd">    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},</span>
+</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd">    ...                    &#39;required&#39;: [&#39;key&#39;]}</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd">    ...     def process_conf(self):</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="sd">    ...         if &#39;key&#39; in self.conf:</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd">    ...             print(f&quot;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&quot;)</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd">    ...     async def run(self):</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd">    ...         print(&quot;Doing something else.&quot;)</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a><span class="sd">    &gt;&gt;&gt; async def test():</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a><span class="sd">    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,</span>
+</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="sd">    ...                    {&#39;key&#39;: &#39;Something&#39;})</span>
+</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a><span class="sd">    ...     print(p.bus)</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a><span class="sd">    ...     print(p.name)</span>
+</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a><span class="sd">    ...     print(p.conf)</span>
+</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test())  # doctest: +ELLIPSIS</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a><span class="sd">    Processing &#39;Something&#39;.</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a><span class="sd">    &lt;controlpi.messagebus.MessageBus object at 0x...&gt;</span>
+</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a><span class="sd">    Test Instance</span>
+</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a><span class="sd">    {&#39;key&#39;: &#39;Something&#39;}</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a>
+</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a><span class="sd">    It also validates the configuration against the schema in CONF_SCHEMA</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a><span class="sd">    and raises ConfException if is not validated.</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a><span class="sd">    &gt;&gt;&gt; async def test():</span>
+</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a><span class="sd">    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,</span>
+</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a><span class="sd">    ...                    {&#39;key&#39;: 42})</span>
+</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a><span class="sd">    Traceback (most recent call last):</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a><span class="sd">      ...</span>
+</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a><span class="sd">    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;</span>
+</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a><span class="sd">    is not valid.</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a><span class="sd">    &gt;&gt;&gt; async def test():</span>
+</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="sd">    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="sd">    ...                    {&#39;key 2&#39;: &#39;Something&#39;})</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="sd">    Traceback (most recent call last):</span>
+</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a><span class="sd">      ...</span>
+</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a><span class="sd">    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;</span>
+</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a><span class="sd">    is not valid.</span>
+</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a>
+</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a><span class="sd">    Finally, it calls process_conf, which is the function that should be</span>
+</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a><span class="sd">    overridden by concrete plugins.</span>
+</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a>
+</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a>    <span class="n">CONF_SCHEMA</span><span class="p">:</span> <span class="n">JSONSchema</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a>
+</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a>    <span class="n">_validate</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[</span><span class="n">PluginConf</span><span class="p">],</span> <span class="n">PluginConf</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
+</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a>
+</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bus</span><span class="p">:</span> <span class="n">MessageBus</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">conf</span><span class="p">:</span> <span class="n">PluginConf</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a>        <span class="c1"># noqa: D107</span>
+</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span> <span class="o">=</span> <span class="n">bus</span>
+</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
+</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_validate</span><span class="p">:</span>
+</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a>            <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_validate</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">CONF_SCHEMA</span><span class="p">)</span>
+</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">conf</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a>        <span class="n">validate</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_validate</span>
+</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a>        <span class="k">assert</span> <span class="n">validate</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
+</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a>        <span class="k">try</span><span class="p">:</span>
+</span><span id="L-181"><a href="#L-181"><span class="linenos">181</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">conf</span> <span class="o">=</span> <span class="n">validate</span><span class="p">(</span><span class="n">conf</span><span class="p">)</span>
+</span><span id="L-182"><a href="#L-182"><span class="linenos">182</span></a>        <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+</span><span id="L-183"><a href="#L-183"><span class="linenos">183</span></a>            <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+</span><span id="L-184"><a href="#L-184"><span class="linenos">184</span></a>            <span class="k">raise</span> <span class="n">ConfException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Configuration for &#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&#39; is not valid.&quot;</span><span class="p">)</span>
+</span><span id="L-185"><a href="#L-185"><span class="linenos">185</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">process_conf</span><span class="p">()</span>
+</span><span id="L-186"><a href="#L-186"><span class="linenos">186</span></a>
+</span><span id="L-187"><a href="#L-187"><span class="linenos">187</span></a>    <span class="nd">@abstractmethod</span>
+</span><span id="L-188"><a href="#L-188"><span class="linenos">188</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-189"><a href="#L-189"><span class="linenos">189</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Process the configuration.</span>
+</span><span id="L-190"><a href="#L-190"><span class="linenos">190</span></a>
+</span><span id="L-191"><a href="#L-191"><span class="linenos">191</span></a><span class="sd">        Abstract method has to be overridden by concrete plugins.</span>
+</span><span id="L-192"><a href="#L-192"><span class="linenos">192</span></a><span class="sd">        process_conf is called at the end of initialisation after the bus</span>
+</span><span id="L-193"><a href="#L-193"><span class="linenos">193</span></a><span class="sd">        and the configuration are available as self.bus and self.conf, but</span>
+</span><span id="L-194"><a href="#L-194"><span class="linenos">194</span></a><span class="sd">        before any of the run coroutines are executed.</span>
+</span><span id="L-195"><a href="#L-195"><span class="linenos">195</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-196"><a href="#L-196"><span class="linenos">196</span></a>        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
+</span><span id="L-197"><a href="#L-197"><span class="linenos">197</span></a>
+</span><span id="L-198"><a href="#L-198"><span class="linenos">198</span></a>    <span class="nd">@abstractmethod</span>
+</span><span id="L-199"><a href="#L-199"><span class="linenos">199</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-200"><a href="#L-200"><span class="linenos">200</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the plugin.</span>
+</span><span id="L-201"><a href="#L-201"><span class="linenos">201</span></a>
+</span><span id="L-202"><a href="#L-202"><span class="linenos">202</span></a><span class="sd">        The coroutine is run concurrently with the message bus and all</span>
+</span><span id="L-203"><a href="#L-203"><span class="linenos">203</span></a><span class="sd">        other plugins. Initial messages and other tasks can be done here.</span>
+</span><span id="L-204"><a href="#L-204"><span class="linenos">204</span></a><span class="sd">        It is also okay to run a plugin-specific infinite loop concurrently</span>
+</span><span id="L-205"><a href="#L-205"><span class="linenos">205</span></a><span class="sd">        with the rest of the system.</span>
+</span><span id="L-206"><a href="#L-206"><span class="linenos">206</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-207"><a href="#L-207"><span class="linenos">207</span></a>        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="JSONSchema">
+                    <div class="attr variable">
+            <span class="name">JSONSchema</span>        =
+<input id="JSONSchema-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="JSONSchema-view-value"></label><span class="default_value">bool | typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]</span>
+
+        
+    </div>
+    <a class="headerlink" href="#JSONSchema"></a>
+    
+    
+
+                </section>
+                <section id="PluginConf">
+                    <div class="attr variable">
+            <span class="name">PluginConf</span>        =
+<span class="default_value">typing.Dict[str, typing.Any]</span>
+
+        
+    </div>
+    <a class="headerlink" href="#PluginConf"></a>
+    
+    
+
+                </section>
+                <section id="ConfException">
+                            <input id="ConfException-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">ConfException</span><wbr>(<span class="base">builtins.Exception</span>):
+
+                <label class="view-source-button" for="ConfException-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#ConfException"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="ConfException-106"><a href="#ConfException-106"><span class="linenos">106</span></a><span class="k">class</span><span class="w"> </span><span class="nc">ConfException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+</span><span id="ConfException-107"><a href="#ConfException-107"><span class="linenos">107</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Raise for errors in plugin configurations.&quot;&quot;&quot;</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Raise for errors in plugin configurations.</p>
+</div>
+
+
+                </section>
+                <section id="BasePlugin">
+                            <input id="BasePlugin-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">BasePlugin</span><wbr>(<span class="base">abc.ABC</span>):
+
+                <label class="view-source-button" for="BasePlugin-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#BasePlugin"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="BasePlugin-110"><a href="#BasePlugin-110"><span class="linenos">110</span></a><span class="k">class</span><span class="w"> </span><span class="nc">BasePlugin</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
+</span><span id="BasePlugin-111"><a href="#BasePlugin-111"><span class="linenos">111</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Base class for all ControlPi plugins.</span>
+</span><span id="BasePlugin-112"><a href="#BasePlugin-112"><span class="linenos">112</span></a>
+</span><span id="BasePlugin-113"><a href="#BasePlugin-113"><span class="linenos">113</span></a><span class="sd">    &gt;&gt;&gt; class TestPlugin(BasePlugin):</span>
+</span><span id="BasePlugin-114"><a href="#BasePlugin-114"><span class="linenos">114</span></a><span class="sd">    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},</span>
+</span><span id="BasePlugin-115"><a href="#BasePlugin-115"><span class="linenos">115</span></a><span class="sd">    ...                    &#39;required&#39;: [&#39;key&#39;]}</span>
+</span><span id="BasePlugin-116"><a href="#BasePlugin-116"><span class="linenos">116</span></a><span class="sd">    ...     def process_conf(self):</span>
+</span><span id="BasePlugin-117"><a href="#BasePlugin-117"><span class="linenos">117</span></a><span class="sd">    ...         if &#39;key&#39; in self.conf:</span>
+</span><span id="BasePlugin-118"><a href="#BasePlugin-118"><span class="linenos">118</span></a><span class="sd">    ...             print(f&quot;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&quot;)</span>
+</span><span id="BasePlugin-119"><a href="#BasePlugin-119"><span class="linenos">119</span></a><span class="sd">    ...     async def run(self):</span>
+</span><span id="BasePlugin-120"><a href="#BasePlugin-120"><span class="linenos">120</span></a><span class="sd">    ...         print(&quot;Doing something else.&quot;)</span>
+</span><span id="BasePlugin-121"><a href="#BasePlugin-121"><span class="linenos">121</span></a>
+</span><span id="BasePlugin-122"><a href="#BasePlugin-122"><span class="linenos">122</span></a><span class="sd">    Initialisation sets the instance variables bus to the given message bus,</span>
+</span><span id="BasePlugin-123"><a href="#BasePlugin-123"><span class="linenos">123</span></a><span class="sd">    name to the given name, and conf to the given configuration:</span>
+</span><span id="BasePlugin-124"><a href="#BasePlugin-124"><span class="linenos">124</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="BasePlugin-125"><a href="#BasePlugin-125"><span class="linenos">125</span></a><span class="sd">    &gt;&gt;&gt; class TestPlugin(BasePlugin):</span>
+</span><span id="BasePlugin-126"><a href="#BasePlugin-126"><span class="linenos">126</span></a><span class="sd">    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},</span>
+</span><span id="BasePlugin-127"><a href="#BasePlugin-127"><span class="linenos">127</span></a><span class="sd">    ...                    &#39;required&#39;: [&#39;key&#39;]}</span>
+</span><span id="BasePlugin-128"><a href="#BasePlugin-128"><span class="linenos">128</span></a><span class="sd">    ...     def process_conf(self):</span>
+</span><span id="BasePlugin-129"><a href="#BasePlugin-129"><span class="linenos">129</span></a><span class="sd">    ...         if &#39;key&#39; in self.conf:</span>
+</span><span id="BasePlugin-130"><a href="#BasePlugin-130"><span class="linenos">130</span></a><span class="sd">    ...             print(f&quot;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&quot;)</span>
+</span><span id="BasePlugin-131"><a href="#BasePlugin-131"><span class="linenos">131</span></a><span class="sd">    ...     async def run(self):</span>
+</span><span id="BasePlugin-132"><a href="#BasePlugin-132"><span class="linenos">132</span></a><span class="sd">    ...         print(&quot;Doing something else.&quot;)</span>
+</span><span id="BasePlugin-133"><a href="#BasePlugin-133"><span class="linenos">133</span></a><span class="sd">    &gt;&gt;&gt; async def test():</span>
+</span><span id="BasePlugin-134"><a href="#BasePlugin-134"><span class="linenos">134</span></a><span class="sd">    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,</span>
+</span><span id="BasePlugin-135"><a href="#BasePlugin-135"><span class="linenos">135</span></a><span class="sd">    ...                    {&#39;key&#39;: &#39;Something&#39;})</span>
+</span><span id="BasePlugin-136"><a href="#BasePlugin-136"><span class="linenos">136</span></a><span class="sd">    ...     print(p.bus)</span>
+</span><span id="BasePlugin-137"><a href="#BasePlugin-137"><span class="linenos">137</span></a><span class="sd">    ...     print(p.name)</span>
+</span><span id="BasePlugin-138"><a href="#BasePlugin-138"><span class="linenos">138</span></a><span class="sd">    ...     print(p.conf)</span>
+</span><span id="BasePlugin-139"><a href="#BasePlugin-139"><span class="linenos">139</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test())  # doctest: +ELLIPSIS</span>
+</span><span id="BasePlugin-140"><a href="#BasePlugin-140"><span class="linenos">140</span></a><span class="sd">    Processing &#39;Something&#39;.</span>
+</span><span id="BasePlugin-141"><a href="#BasePlugin-141"><span class="linenos">141</span></a><span class="sd">    &lt;controlpi.messagebus.MessageBus object at 0x...&gt;</span>
+</span><span id="BasePlugin-142"><a href="#BasePlugin-142"><span class="linenos">142</span></a><span class="sd">    Test Instance</span>
+</span><span id="BasePlugin-143"><a href="#BasePlugin-143"><span class="linenos">143</span></a><span class="sd">    {&#39;key&#39;: &#39;Something&#39;}</span>
+</span><span id="BasePlugin-144"><a href="#BasePlugin-144"><span class="linenos">144</span></a>
+</span><span id="BasePlugin-145"><a href="#BasePlugin-145"><span class="linenos">145</span></a><span class="sd">    It also validates the configuration against the schema in CONF_SCHEMA</span>
+</span><span id="BasePlugin-146"><a href="#BasePlugin-146"><span class="linenos">146</span></a><span class="sd">    and raises ConfException if is not validated.</span>
+</span><span id="BasePlugin-147"><a href="#BasePlugin-147"><span class="linenos">147</span></a><span class="sd">    &gt;&gt;&gt; async def test():</span>
+</span><span id="BasePlugin-148"><a href="#BasePlugin-148"><span class="linenos">148</span></a><span class="sd">    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,</span>
+</span><span id="BasePlugin-149"><a href="#BasePlugin-149"><span class="linenos">149</span></a><span class="sd">    ...                    {&#39;key&#39;: 42})</span>
+</span><span id="BasePlugin-150"><a href="#BasePlugin-150"><span class="linenos">150</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="BasePlugin-151"><a href="#BasePlugin-151"><span class="linenos">151</span></a><span class="sd">    Traceback (most recent call last):</span>
+</span><span id="BasePlugin-152"><a href="#BasePlugin-152"><span class="linenos">152</span></a><span class="sd">      ...</span>
+</span><span id="BasePlugin-153"><a href="#BasePlugin-153"><span class="linenos">153</span></a><span class="sd">    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;</span>
+</span><span id="BasePlugin-154"><a href="#BasePlugin-154"><span class="linenos">154</span></a><span class="sd">    is not valid.</span>
+</span><span id="BasePlugin-155"><a href="#BasePlugin-155"><span class="linenos">155</span></a><span class="sd">    &gt;&gt;&gt; async def test():</span>
+</span><span id="BasePlugin-156"><a href="#BasePlugin-156"><span class="linenos">156</span></a><span class="sd">    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,</span>
+</span><span id="BasePlugin-157"><a href="#BasePlugin-157"><span class="linenos">157</span></a><span class="sd">    ...                    {&#39;key 2&#39;: &#39;Something&#39;})</span>
+</span><span id="BasePlugin-158"><a href="#BasePlugin-158"><span class="linenos">158</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="BasePlugin-159"><a href="#BasePlugin-159"><span class="linenos">159</span></a><span class="sd">    Traceback (most recent call last):</span>
+</span><span id="BasePlugin-160"><a href="#BasePlugin-160"><span class="linenos">160</span></a><span class="sd">      ...</span>
+</span><span id="BasePlugin-161"><a href="#BasePlugin-161"><span class="linenos">161</span></a><span class="sd">    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;</span>
+</span><span id="BasePlugin-162"><a href="#BasePlugin-162"><span class="linenos">162</span></a><span class="sd">    is not valid.</span>
+</span><span id="BasePlugin-163"><a href="#BasePlugin-163"><span class="linenos">163</span></a>
+</span><span id="BasePlugin-164"><a href="#BasePlugin-164"><span class="linenos">164</span></a><span class="sd">    Finally, it calls process_conf, which is the function that should be</span>
+</span><span id="BasePlugin-165"><a href="#BasePlugin-165"><span class="linenos">165</span></a><span class="sd">    overridden by concrete plugins.</span>
+</span><span id="BasePlugin-166"><a href="#BasePlugin-166"><span class="linenos">166</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="BasePlugin-167"><a href="#BasePlugin-167"><span class="linenos">167</span></a>
+</span><span id="BasePlugin-168"><a href="#BasePlugin-168"><span class="linenos">168</span></a>    <span class="n">CONF_SCHEMA</span><span class="p">:</span> <span class="n">JSONSchema</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="BasePlugin-169"><a href="#BasePlugin-169"><span class="linenos">169</span></a>
+</span><span id="BasePlugin-170"><a href="#BasePlugin-170"><span class="linenos">170</span></a>    <span class="n">_validate</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[</span><span class="n">PluginConf</span><span class="p">],</span> <span class="n">PluginConf</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
+</span><span id="BasePlugin-171"><a href="#BasePlugin-171"><span class="linenos">171</span></a>
+</span><span id="BasePlugin-172"><a href="#BasePlugin-172"><span class="linenos">172</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bus</span><span class="p">:</span> <span class="n">MessageBus</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">conf</span><span class="p">:</span> <span class="n">PluginConf</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="BasePlugin-173"><a href="#BasePlugin-173"><span class="linenos">173</span></a>        <span class="c1"># noqa: D107</span>
+</span><span id="BasePlugin-174"><a href="#BasePlugin-174"><span class="linenos">174</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span> <span class="o">=</span> <span class="n">bus</span>
+</span><span id="BasePlugin-175"><a href="#BasePlugin-175"><span class="linenos">175</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
+</span><span id="BasePlugin-176"><a href="#BasePlugin-176"><span class="linenos">176</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_validate</span><span class="p">:</span>
+</span><span id="BasePlugin-177"><a href="#BasePlugin-177"><span class="linenos">177</span></a>            <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_validate</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">CONF_SCHEMA</span><span class="p">)</span>
+</span><span id="BasePlugin-178"><a href="#BasePlugin-178"><span class="linenos">178</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">conf</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="BasePlugin-179"><a href="#BasePlugin-179"><span class="linenos">179</span></a>        <span class="n">validate</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_validate</span>
+</span><span id="BasePlugin-180"><a href="#BasePlugin-180"><span class="linenos">180</span></a>        <span class="k">assert</span> <span class="n">validate</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
+</span><span id="BasePlugin-181"><a href="#BasePlugin-181"><span class="linenos">181</span></a>        <span class="k">try</span><span class="p">:</span>
+</span><span id="BasePlugin-182"><a href="#BasePlugin-182"><span class="linenos">182</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">conf</span> <span class="o">=</span> <span class="n">validate</span><span class="p">(</span><span class="n">conf</span><span class="p">)</span>
+</span><span id="BasePlugin-183"><a href="#BasePlugin-183"><span class="linenos">183</span></a>        <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+</span><span id="BasePlugin-184"><a href="#BasePlugin-184"><span class="linenos">184</span></a>            <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+</span><span id="BasePlugin-185"><a href="#BasePlugin-185"><span class="linenos">185</span></a>            <span class="k">raise</span> <span class="n">ConfException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Configuration for &#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&#39; is not valid.&quot;</span><span class="p">)</span>
+</span><span id="BasePlugin-186"><a href="#BasePlugin-186"><span class="linenos">186</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">process_conf</span><span class="p">()</span>
+</span><span id="BasePlugin-187"><a href="#BasePlugin-187"><span class="linenos">187</span></a>
+</span><span id="BasePlugin-188"><a href="#BasePlugin-188"><span class="linenos">188</span></a>    <span class="nd">@abstractmethod</span>
+</span><span id="BasePlugin-189"><a href="#BasePlugin-189"><span class="linenos">189</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="BasePlugin-190"><a href="#BasePlugin-190"><span class="linenos">190</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Process the configuration.</span>
+</span><span id="BasePlugin-191"><a href="#BasePlugin-191"><span class="linenos">191</span></a>
+</span><span id="BasePlugin-192"><a href="#BasePlugin-192"><span class="linenos">192</span></a><span class="sd">        Abstract method has to be overridden by concrete plugins.</span>
+</span><span id="BasePlugin-193"><a href="#BasePlugin-193"><span class="linenos">193</span></a><span class="sd">        process_conf is called at the end of initialisation after the bus</span>
+</span><span id="BasePlugin-194"><a href="#BasePlugin-194"><span class="linenos">194</span></a><span class="sd">        and the configuration are available as self.bus and self.conf, but</span>
+</span><span id="BasePlugin-195"><a href="#BasePlugin-195"><span class="linenos">195</span></a><span class="sd">        before any of the run coroutines are executed.</span>
+</span><span id="BasePlugin-196"><a href="#BasePlugin-196"><span class="linenos">196</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="BasePlugin-197"><a href="#BasePlugin-197"><span class="linenos">197</span></a>        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
+</span><span id="BasePlugin-198"><a href="#BasePlugin-198"><span class="linenos">198</span></a>
+</span><span id="BasePlugin-199"><a href="#BasePlugin-199"><span class="linenos">199</span></a>    <span class="nd">@abstractmethod</span>
+</span><span id="BasePlugin-200"><a href="#BasePlugin-200"><span class="linenos">200</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="BasePlugin-201"><a href="#BasePlugin-201"><span class="linenos">201</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the plugin.</span>
+</span><span id="BasePlugin-202"><a href="#BasePlugin-202"><span class="linenos">202</span></a>
+</span><span id="BasePlugin-203"><a href="#BasePlugin-203"><span class="linenos">203</span></a><span class="sd">        The coroutine is run concurrently with the message bus and all</span>
+</span><span id="BasePlugin-204"><a href="#BasePlugin-204"><span class="linenos">204</span></a><span class="sd">        other plugins. Initial messages and other tasks can be done here.</span>
+</span><span id="BasePlugin-205"><a href="#BasePlugin-205"><span class="linenos">205</span></a><span class="sd">        It is also okay to run a plugin-specific infinite loop concurrently</span>
+</span><span id="BasePlugin-206"><a href="#BasePlugin-206"><span class="linenos">206</span></a><span class="sd">        with the rest of the system.</span>
+</span><span id="BasePlugin-207"><a href="#BasePlugin-207"><span class="linenos">207</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="BasePlugin-208"><a href="#BasePlugin-208"><span class="linenos">208</span></a>        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Base class for all ControlPi plugins.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">TestPlugin</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span>
+<span class="gp">... </span>                   <span class="s1">&#39;required&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]}</span>
+<span class="gp">... </span>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="k">if</span> <span class="s1">&#39;key&#39;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+<span class="gp">... </span>            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing &#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&#39;.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Doing something else.&quot;</span><span class="p">)</span>
+</code></pre>
+</div>
+
+<p>Initialisation sets the instance variables bus to the given message bus,
+name to the given name, and conf to the given configuration:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">TestPlugin</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span>
+<span class="gp">... </span>                   <span class="s1">&#39;required&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]}</span>
+<span class="gp">... </span>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="k">if</span> <span class="s1">&#39;key&#39;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+<span class="gp">... </span>            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing &#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&#39;.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Doing something else.&quot;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">p</span> <span class="o">=</span> <span class="n">TestPlugin</span><span class="p">(</span><span class="n">MessageBus</span><span class="p">(),</span> <span class="s1">&#39;Test Instance&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;Something&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">bus</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">conf</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test</span><span class="p">())</span>  <span class="c1"># doctest: +ELLIPSIS</span>
+<span class="go">Processing &#39;Something&#39;.</span>
+<span class="go">&lt;<a href="messagebus.html#MessageBus">controlpi.messagebus.MessageBus</a> object at 0x...&gt;</span>
+<span class="go">Test Instance</span>
+<span class="go">{&#39;key&#39;: &#39;Something&#39;}</span>
+</code></pre>
+</div>
+
+<p>It also validates the configuration against the schema in CONF_SCHEMA
+and raises ConfException if is not validated.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">p</span> <span class="o">=</span> <span class="n">TestPlugin</span><span class="p">(</span><span class="n">MessageBus</span><span class="p">(),</span> <span class="s1">&#39;Test Instance&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">baseplugin.ConfException</span>: <span class="n">Configuration for &#39;Test Instance&#39;</span>
+<span class="x">is not valid.</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">p</span> <span class="o">=</span> <span class="n">TestPlugin</span><span class="p">(</span><span class="n">MessageBus</span><span class="p">(),</span> <span class="s1">&#39;Test Instance&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="p">{</span><span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;Something&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">test</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">baseplugin.ConfException</span>: <span class="n">Configuration for &#39;Test Instance&#39;</span>
+<span class="x">is not valid.</span>
+</code></pre>
+</div>
+
+<p>Finally, it calls process_conf, which is the function that should be
+overridden by concrete plugins.</p>
+</div>
+
+
+                            <div id="BasePlugin.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span><span class="annotation">: bool | Dict[str, None | str | int | float | bool | Dict[str, Any] | List[Any]]</span>        =
+<span class="default_value">False</span>
+
+        
+    </div>
+    <a class="headerlink" href="#BasePlugin.CONF_SCHEMA"></a>
+    
+    
+
+                            </div>
+                            <div id="BasePlugin.bus" class="classattr">
+                                <div class="attr variable">
+            <span class="name">bus</span>
+
+        
+    </div>
+    <a class="headerlink" href="#BasePlugin.bus"></a>
+    
+    
+
+                            </div>
+                            <div id="BasePlugin.name" class="classattr">
+                                <div class="attr variable">
+            <span class="name">name</span>
+
+        
+    </div>
+    <a class="headerlink" href="#BasePlugin.name"></a>
+    
+    
+
+                            </div>
+                            <div id="BasePlugin.conf" class="classattr">
+                                <div class="attr variable">
+            <span class="name">conf</span>
+
+        
+    </div>
+    <a class="headerlink" href="#BasePlugin.conf"></a>
+    
+    
+
+                            </div>
+                            <div id="BasePlugin.process_conf" class="classattr">
+                                        <input id="BasePlugin.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+                    <div class="decorator decorator-abstractmethod">@abstractmethod</div>
+
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="BasePlugin.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#BasePlugin.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="BasePlugin.process_conf-188"><a href="#BasePlugin.process_conf-188"><span class="linenos">188</span></a>    <span class="nd">@abstractmethod</span>
+</span><span id="BasePlugin.process_conf-189"><a href="#BasePlugin.process_conf-189"><span class="linenos">189</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="BasePlugin.process_conf-190"><a href="#BasePlugin.process_conf-190"><span class="linenos">190</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Process the configuration.</span>
+</span><span id="BasePlugin.process_conf-191"><a href="#BasePlugin.process_conf-191"><span class="linenos">191</span></a>
+</span><span id="BasePlugin.process_conf-192"><a href="#BasePlugin.process_conf-192"><span class="linenos">192</span></a><span class="sd">        Abstract method has to be overridden by concrete plugins.</span>
+</span><span id="BasePlugin.process_conf-193"><a href="#BasePlugin.process_conf-193"><span class="linenos">193</span></a><span class="sd">        process_conf is called at the end of initialisation after the bus</span>
+</span><span id="BasePlugin.process_conf-194"><a href="#BasePlugin.process_conf-194"><span class="linenos">194</span></a><span class="sd">        and the configuration are available as self.bus and self.conf, but</span>
+</span><span id="BasePlugin.process_conf-195"><a href="#BasePlugin.process_conf-195"><span class="linenos">195</span></a><span class="sd">        before any of the run coroutines are executed.</span>
+</span><span id="BasePlugin.process_conf-196"><a href="#BasePlugin.process_conf-196"><span class="linenos">196</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="BasePlugin.process_conf-197"><a href="#BasePlugin.process_conf-197"><span class="linenos">197</span></a>        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Process the configuration.</p>
+
+<p>Abstract method has to be overridden by concrete plugins.
+process_conf is called at the end of initialisation after the bus
+and the configuration are available as self.bus and self.conf, but
+before any of the run coroutines are executed.</p>
+</div>
+
+
+                            </div>
+                            <div id="BasePlugin.run" class="classattr">
+                                        <input id="BasePlugin.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+                    <div class="decorator decorator-abstractmethod">@abstractmethod</div>
+
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="BasePlugin.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#BasePlugin.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="BasePlugin.run-199"><a href="#BasePlugin.run-199"><span class="linenos">199</span></a>    <span class="nd">@abstractmethod</span>
+</span><span id="BasePlugin.run-200"><a href="#BasePlugin.run-200"><span class="linenos">200</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="BasePlugin.run-201"><a href="#BasePlugin.run-201"><span class="linenos">201</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the plugin.</span>
+</span><span id="BasePlugin.run-202"><a href="#BasePlugin.run-202"><span class="linenos">202</span></a>
+</span><span id="BasePlugin.run-203"><a href="#BasePlugin.run-203"><span class="linenos">203</span></a><span class="sd">        The coroutine is run concurrently with the message bus and all</span>
+</span><span id="BasePlugin.run-204"><a href="#BasePlugin.run-204"><span class="linenos">204</span></a><span class="sd">        other plugins. Initial messages and other tasks can be done here.</span>
+</span><span id="BasePlugin.run-205"><a href="#BasePlugin.run-205"><span class="linenos">205</span></a><span class="sd">        It is also okay to run a plugin-specific infinite loop concurrently</span>
+</span><span id="BasePlugin.run-206"><a href="#BasePlugin.run-206"><span class="linenos">206</span></a><span class="sd">        with the rest of the system.</span>
+</span><span id="BasePlugin.run-207"><a href="#BasePlugin.run-207"><span class="linenos">207</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="BasePlugin.run-208"><a href="#BasePlugin.run-208"><span class="linenos">208</span></a>        <span class="k">raise</span> <span class="ne">NotImplementedError</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run the plugin.</p>
+
+<p>The coroutine is run concurrently with the message bus and all
+other plugins. Initial messages and other tasks can be done here.
+It is also okay to run a plugin-specific infinite loop concurrently
+with the rest of the system.</p>
+</div>
+
+
+                            </div>
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "../search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `../${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi/messagebus.html b/doc/api/controlpi/messagebus.html
new file mode 100644 (file)
index 0000000..5ac6739
--- /dev/null
@@ -0,0 +1,5480 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi.messagebus API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="../controlpi.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;controlpi</a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="variable" href="#MessageValue">MessageValue</a>
+            </li>
+            <li>
+                    <a class="variable" href="#JSONSchema">JSONSchema</a>
+            </li>
+            <li>
+                    <a class="variable" href="#MessageCallback">MessageCallback</a>
+            </li>
+            <li>
+                    <a class="function" href="#register_schema">register_schema</a>
+            </li>
+            <li>
+                    <a class="function" href="#validate">validate</a>
+            </li>
+            <li>
+                    <a class="class" href="#Message">Message</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="function" href="#Message.__init__">Message</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Message.check_value">check_value</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Message.update">update</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Message.setdefault">setdefault</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#MessageTemplate">MessageTemplate</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="function" href="#MessageTemplate.__init__">MessageTemplate</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageTemplate.from_message">from_message</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageTemplate.update">update</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageTemplate.setdefault">setdefault</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageTemplate.check">check</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#TemplateRegistry">TemplateRegistry</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="function" href="#TemplateRegistry.__init__">TemplateRegistry</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#TemplateRegistry.insert">insert</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#TemplateRegistry.delete">delete</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#TemplateRegistry.check">check</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#TemplateRegistry.get">get</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#TemplateRegistry.get_callbacks">get_callbacks</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#TemplateRegistry.get_templates">get_templates</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#BusException">BusException</a>
+                            <ul class="memberlist">
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#MessageBus">MessageBus</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="function" href="#MessageBus.__init__">MessageBus</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageBus.register">register</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageBus.unregister">unregister</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageBus.run">run</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageBus.send">send</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#MessageBus.send_nowait">send_nowait</a>
+                        </li>
+                </ul>
+
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+<a href="./../controlpi.html">controlpi</a><wbr>.messagebus    </h1>
+
+                        <div class="docstring"><p>Provide an asynchronous message bus.</p>
+
+<p>A message is a dictionary with string keys and string, integer, float,
+Boolean, dictionary, or list values, where the inner dictionaries again
+have string keys and these values and the inner lists also have elements of
+these types. All messages have a special key 'sender' with the name of the
+sending client as string value, which is set by the constructor:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value 1&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="p">[</span><span class="s1">&#39;key 2&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;value 2&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</code></pre>
+</div>
+
+<p>A message template is a mapping from string keys to JSON schemas as values.
+A message template matches a message if all keys of the template are
+contained in the message and the values in the message validate against the
+respective schemas. An empty mapping therefore matches all messages.</p>
+
+<p>The bus executes asynchronous callbacks for all messages to be received by
+a client. We use a simple callback printing the message in all examples:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span><span class="w"> </span><span class="nf">callback_for_receiver</span><span class="p">(</span><span class="n">receiver</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">receiver</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">return</span> <span class="n">callback</span>
+</code></pre>
+</div>
+
+<p>Clients can be registered at the bus with a name, lists of message templates
+they want to use for sending and receiving and a callback function for
+receiving. An empty list of templates means that the client does not want to
+send or receive any messages, respectively. A list with an empty template
+means that it wants to send arbitrary or receive all messages, respectively:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">setup</span><span class="p">(</span><span class="n">bus</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Logger&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({})],</span>
+<span class="gp">... </span>                   <span class="n">callback_for_receiver</span><span class="p">(</span><span class="s1">&#39;Logger&#39;</span><span class="p">))])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback_for_receiver</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">))])</span>
+</code></pre>
+</div>
+
+<p>While most clients should always use their own name for sending, this is not
+enforced and debugging or management clients could send messages on behalf
+of arbitrary client names.</p>
+
+<p>The name of a client has to be unique and is not allowed to be empty
+(otherwise registration fails).</p>
+
+<p>The empty name is used to refer to the bus itself. The bus sends messages
+for registrations and deregistrations of clients containing their complete
+interface of send and receive templates. This can be used to allow dynamic
+(debug) clients to deal with arbitrary configurations of clients. The bus
+also reacts to 'get clients' command messages by sending the complete
+information of all currently registered clients.</p>
+
+<p>Clients can send to the bus with the send function. Each message has to
+declare a sender. The send templates of that sender are checked for a
+template matching the message:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send</span><span class="p">(</span><span class="n">bus</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Sending messages.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;Test&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">})</span>
+</code></pre>
+</div>
+
+<p>The run function executes the message bus forever. If we want to stop it, we
+have to explicitly cancel the task:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">setup</span><span class="p">(</span><span class="n">bus</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">send</span><span class="p">(</span><span class="n">bus</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">bus_task</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">Sending messages.</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+<span class="go">Client 1: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+                        <input id="mod-messagebus-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-messagebus-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">   1</span></a><span class="sd">&quot;&quot;&quot;Provide an asynchronous message bus.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">   2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">   3</span></a><span class="sd">A message is a dictionary with string keys and string, integer, float,</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">   4</span></a><span class="sd">Boolean, dictionary, or list values, where the inner dictionaries again</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">   5</span></a><span class="sd">have string keys and these values and the inner lists also have elements of</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">   6</span></a><span class="sd">these types. All messages have a special key &#39;sender&#39; with the name of the</span>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">   7</span></a><span class="sd">sending client as string value, which is set by the constructor:</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">   8</span></a><span class="sd">&gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">   9</span></a><span class="sd">&gt;&gt;&gt; m[&#39;key 2&#39;] = &#39;value 2&#39;</span>
+</span><span id="L-10"><a href="#L-10"><span class="linenos">  10</span></a><span class="sd">&gt;&gt;&gt; print(m)</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos">  11</span></a><span class="sd">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos">  12</span></a>
+</span><span id="L-13"><a href="#L-13"><span class="linenos">  13</span></a><span class="sd">A message template is a mapping from string keys to JSON schemas as values.</span>
+</span><span id="L-14"><a href="#L-14"><span class="linenos">  14</span></a><span class="sd">A message template matches a message if all keys of the template are</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos">  15</span></a><span class="sd">contained in the message and the values in the message validate against the</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos">  16</span></a><span class="sd">respective schemas. An empty mapping therefore matches all messages.</span>
+</span><span id="L-17"><a href="#L-17"><span class="linenos">  17</span></a>
+</span><span id="L-18"><a href="#L-18"><span class="linenos">  18</span></a><span class="sd">The bus executes asynchronous callbacks for all messages to be received by</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos">  19</span></a><span class="sd">a client. We use a simple callback printing the message in all examples:</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos">  20</span></a><span class="sd">&gt;&gt;&gt; def callback_for_receiver(receiver):</span>
+</span><span id="L-21"><a href="#L-21"><span class="linenos">  21</span></a><span class="sd">...     async def callback(message):</span>
+</span><span id="L-22"><a href="#L-22"><span class="linenos">  22</span></a><span class="sd">...         print(f&quot;{receiver}: {message}&quot;)</span>
+</span><span id="L-23"><a href="#L-23"><span class="linenos">  23</span></a><span class="sd">...     return callback</span>
+</span><span id="L-24"><a href="#L-24"><span class="linenos">  24</span></a>
+</span><span id="L-25"><a href="#L-25"><span class="linenos">  25</span></a><span class="sd">Clients can be registered at the bus with a name, lists of message templates</span>
+</span><span id="L-26"><a href="#L-26"><span class="linenos">  26</span></a><span class="sd">they want to use for sending and receiving and a callback function for</span>
+</span><span id="L-27"><a href="#L-27"><span class="linenos">  27</span></a><span class="sd">receiving. An empty list of templates means that the client does not want to</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos">  28</span></a><span class="sd">send or receive any messages, respectively. A list with an empty template</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos">  29</span></a><span class="sd">means that it wants to send arbitrary or receive all messages, respectively:</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos">  30</span></a><span class="sd">&gt;&gt;&gt; async def setup(bus):</span>
+</span><span id="L-31"><a href="#L-31"><span class="linenos">  31</span></a><span class="sd">...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos">  32</span></a><span class="sd">...                  [],</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos">  33</span></a><span class="sd">...                  [([MessageTemplate({})],</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos">  34</span></a><span class="sd">...                    callback_for_receiver(&#39;Logger&#39;))])</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos">  35</span></a><span class="sd">...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-36"><a href="#L-36"><span class="linenos">  36</span></a><span class="sd">...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos">  37</span></a><span class="sd">...                  [([MessageTemplate({&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="L-38"><a href="#L-38"><span class="linenos">  38</span></a><span class="sd">...                    callback_for_receiver(&#39;Client 1&#39;))])</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos">  39</span></a>
+</span><span id="L-40"><a href="#L-40"><span class="linenos">  40</span></a><span class="sd">While most clients should always use their own name for sending, this is not</span>
+</span><span id="L-41"><a href="#L-41"><span class="linenos">  41</span></a><span class="sd">enforced and debugging or management clients could send messages on behalf</span>
+</span><span id="L-42"><a href="#L-42"><span class="linenos">  42</span></a><span class="sd">of arbitrary client names.</span>
+</span><span id="L-43"><a href="#L-43"><span class="linenos">  43</span></a>
+</span><span id="L-44"><a href="#L-44"><span class="linenos">  44</span></a><span class="sd">The name of a client has to be unique and is not allowed to be empty</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos">  45</span></a><span class="sd">(otherwise registration fails).</span>
+</span><span id="L-46"><a href="#L-46"><span class="linenos">  46</span></a>
+</span><span id="L-47"><a href="#L-47"><span class="linenos">  47</span></a><span class="sd">The empty name is used to refer to the bus itself. The bus sends messages</span>
+</span><span id="L-48"><a href="#L-48"><span class="linenos">  48</span></a><span class="sd">for registrations and deregistrations of clients containing their complete</span>
+</span><span id="L-49"><a href="#L-49"><span class="linenos">  49</span></a><span class="sd">interface of send and receive templates. This can be used to allow dynamic</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos">  50</span></a><span class="sd">(debug) clients to deal with arbitrary configurations of clients. The bus</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos">  51</span></a><span class="sd">also reacts to &#39;get clients&#39; command messages by sending the complete</span>
+</span><span id="L-52"><a href="#L-52"><span class="linenos">  52</span></a><span class="sd">information of all currently registered clients.</span>
+</span><span id="L-53"><a href="#L-53"><span class="linenos">  53</span></a>
+</span><span id="L-54"><a href="#L-54"><span class="linenos">  54</span></a><span class="sd">Clients can send to the bus with the send function. Each message has to</span>
+</span><span id="L-55"><a href="#L-55"><span class="linenos">  55</span></a><span class="sd">declare a sender. The send templates of that sender are checked for a</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos">  56</span></a><span class="sd">template matching the message:</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos">  57</span></a><span class="sd">&gt;&gt;&gt; async def send(bus):</span>
+</span><span id="L-58"><a href="#L-58"><span class="linenos">  58</span></a><span class="sd">...     print(&quot;Sending messages.&quot;)</span>
+</span><span id="L-59"><a href="#L-59"><span class="linenos">  59</span></a><span class="sd">...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos">  60</span></a><span class="sd">...     await bus.send({&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos">  61</span></a>
+</span><span id="L-62"><a href="#L-62"><span class="linenos">  62</span></a><span class="sd">The run function executes the message bus forever. If we want to stop it, we</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos">  63</span></a><span class="sd">have to explicitly cancel the task:</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos">  64</span></a><span class="sd">&gt;&gt;&gt; async def main():</span>
+</span><span id="L-65"><a href="#L-65"><span class="linenos">  65</span></a><span class="sd">...     bus = MessageBus()</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos">  66</span></a><span class="sd">...     await setup(bus)</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos">  67</span></a><span class="sd">...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="L-68"><a href="#L-68"><span class="linenos">  68</span></a><span class="sd">...     await send(bus)</span>
+</span><span id="L-69"><a href="#L-69"><span class="linenos">  69</span></a><span class="sd">...     await asyncio.sleep(0)</span>
+</span><span id="L-70"><a href="#L-70"><span class="linenos">  70</span></a><span class="sd">...     bus_task.cancel()</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos">  71</span></a><span class="sd">...     try:</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos">  72</span></a><span class="sd">...         await bus_task</span>
+</span><span id="L-73"><a href="#L-73"><span class="linenos">  73</span></a><span class="sd">...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos">  74</span></a><span class="sd">...         pass</span>
+</span><span id="L-75"><a href="#L-75"><span class="linenos">  75</span></a><span class="sd">&gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-76"><a href="#L-76"><span class="linenos">  76</span></a><span class="sd">Sending messages.</span>
+</span><span id="L-77"><a href="#L-77"><span class="linenos">  77</span></a><span class="sd">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos">  78</span></a><span class="sd">         &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos">  79</span></a><span class="sd">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+</span><span id="L-80"><a href="#L-80"><span class="linenos">  80</span></a><span class="sd">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos">  81</span></a><span class="sd">         &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-82"><a href="#L-82"><span class="linenos">  82</span></a><span class="sd">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-83"><a href="#L-83"><span class="linenos">  83</span></a><span class="sd">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos">  84</span></a><span class="sd">Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="L-85"><a href="#L-85"><span class="linenos">  85</span></a><span class="sd">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos">  86</span></a><span class="sd">Client 1: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="L-87"><a href="#L-87"><span class="linenos">  87</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-88"><a href="#L-88"><span class="linenos">  88</span></a>
+</span><span id="L-89"><a href="#L-89"><span class="linenos">  89</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+</span><span id="L-90"><a href="#L-90"><span class="linenos">  90</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
+</span><span id="L-91"><a href="#L-91"><span class="linenos">  91</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">fastjsonschema</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos">  92</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
+</span><span id="L-93"><a href="#L-93"><span class="linenos">  93</span></a>
+</span><span id="L-94"><a href="#L-94"><span class="linenos">  94</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
+</span><span id="L-95"><a href="#L-95"><span class="linenos">  95</span></a>    <span class="n">Union</span><span class="p">,</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos">  96</span></a>    <span class="n">Dict</span><span class="p">,</span>
+</span><span id="L-97"><a href="#L-97"><span class="linenos">  97</span></a>    <span class="n">List</span><span class="p">,</span>
+</span><span id="L-98"><a href="#L-98"><span class="linenos">  98</span></a>    <span class="n">Any</span><span class="p">,</span>
+</span><span id="L-99"><a href="#L-99"><span class="linenos">  99</span></a>    <span class="n">Callable</span><span class="p">,</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos"> 100</span></a>    <span class="n">Coroutine</span><span class="p">,</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos"> 101</span></a>    <span class="n">Optional</span><span class="p">,</span>
+</span><span id="L-102"><a href="#L-102"><span class="linenos"> 102</span></a>    <span class="n">Iterable</span><span class="p">,</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos"> 103</span></a>    <span class="n">Tuple</span><span class="p">,</span>
+</span><span id="L-104"><a href="#L-104"><span class="linenos"> 104</span></a><span class="p">)</span>
+</span><span id="L-105"><a href="#L-105"><span class="linenos"> 105</span></a>
+</span><span id="L-106"><a href="#L-106"><span class="linenos"> 106</span></a><span class="n">MessageValue</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]</span>
+</span><span id="L-107"><a href="#L-107"><span class="linenos"> 107</span></a><span class="c1"># Should really be:</span>
+</span><span id="L-108"><a href="#L-108"><span class="linenos"> 108</span></a><span class="c1"># MessageValue = Union[None, str, int, float, bool,</span>
+</span><span id="L-109"><a href="#L-109"><span class="linenos"> 109</span></a><span class="c1">#                      Dict[str, &#39;MessageValue&#39;], List[&#39;MessageValue&#39;]]</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos"> 110</span></a><span class="c1"># But mypy does not support recursion by now:</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos"> 111</span></a><span class="c1"># https://github.com/python/mypy/issues/731</span>
+</span><span id="L-112"><a href="#L-112"><span class="linenos"> 112</span></a><span class="n">JSONSchema</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MessageValue</span><span class="p">]]</span>
+</span><span id="L-113"><a href="#L-113"><span class="linenos"> 113</span></a><span class="c1"># Could be even more specific.</span>
+</span><span id="L-114"><a href="#L-114"><span class="linenos"> 114</span></a><span class="n">MessageCallback</span> <span class="o">=</span> <span class="n">Callable</span><span class="p">[[</span><span class="s2">&quot;Message&quot;</span><span class="p">],</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="kc">None</span><span class="p">]]</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos"> 115</span></a>
+</span><span id="L-116"><a href="#L-116"><span class="linenos"> 116</span></a>
+</span><span id="L-117"><a href="#L-117"><span class="linenos"> 117</span></a><span class="c1"># Global cache of JSON schema validation functions:</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos"> 118</span></a><span class="n">_validates</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">MessageValue</span><span class="p">],</span> <span class="n">MessageValue</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-119"><a href="#L-119"><span class="linenos"> 119</span></a>
+</span><span id="L-120"><a href="#L-120"><span class="linenos"> 120</span></a>
+</span><span id="L-121"><a href="#L-121"><span class="linenos"> 121</span></a><span class="k">def</span><span class="w"> </span><span class="nf">register_schema</span><span class="p">(</span><span class="n">schema</span><span class="p">:</span> <span class="n">JSONSchema</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="L-122"><a href="#L-122"><span class="linenos"> 122</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Register the given JSON schema in the global cache.&quot;&quot;&quot;</span>
+</span><span id="L-123"><a href="#L-123"><span class="linenos"> 123</span></a>    <span class="k">global</span> <span class="n">_validates</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos"> 124</span></a>    <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos"> 125</span></a>    <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_validates</span><span class="p">:</span>
+</span><span id="L-126"><a href="#L-126"><span class="linenos"> 126</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)):</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos"> 127</span></a>            <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos"> 128</span></a>        <span class="k">try</span><span class="p">:</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos"> 129</span></a>            <span class="n">_validates</span><span class="p">[</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos"> 130</span></a>        <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaDefinitionException</span><span class="p">:</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos"> 131</span></a>            <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos"> 132</span></a>    <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos"> 133</span></a>
+</span><span id="L-134"><a href="#L-134"><span class="linenos"> 134</span></a>
+</span><span id="L-135"><a href="#L-135"><span class="linenos"> 135</span></a><span class="k">def</span><span class="w"> </span><span class="nf">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos"> 136</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Validate the given MessageValue against the given JSON schema string.&quot;&quot;&quot;</span>
+</span><span id="L-137"><a href="#L-137"><span class="linenos"> 137</span></a>    <span class="k">global</span> <span class="n">_validates</span>
+</span><span id="L-138"><a href="#L-138"><span class="linenos"> 138</span></a>    <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_validates</span><span class="p">:</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos"> 139</span></a>        <span class="n">schema</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">schema_string</span><span class="p">)</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos"> 140</span></a>        <span class="n">_validates</span><span class="p">[</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="L-141"><a href="#L-141"><span class="linenos"> 141</span></a>    <span class="n">validate</span> <span class="o">=</span> <span class="n">_validates</span><span class="p">[</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="L-142"><a href="#L-142"><span class="linenos"> 142</span></a>    <span class="k">try</span><span class="p">:</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos"> 143</span></a>        <span class="n">validate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+</span><span id="L-144"><a href="#L-144"><span class="linenos"> 144</span></a>    <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaException</span><span class="p">:</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos"> 145</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos"> 146</span></a>    <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-147"><a href="#L-147"><span class="linenos"> 147</span></a>
+</span><span id="L-148"><a href="#L-148"><span class="linenos"> 148</span></a>
+</span><span id="L-149"><a href="#L-149"><span class="linenos"> 149</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Message</span><span class="p">(</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MessageValue</span><span class="p">]):</span>
+</span><span id="L-150"><a href="#L-150"><span class="linenos"> 150</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define arbitrary message.</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos"> 151</span></a>
+</span><span id="L-152"><a href="#L-152"><span class="linenos"> 152</span></a><span class="sd">    Messages are dictionaries with string keys and values that are strings,</span>
+</span><span id="L-153"><a href="#L-153"><span class="linenos"> 153</span></a><span class="sd">    integers, floats, Booleans, dictionaries that recursively have string</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos"> 154</span></a><span class="sd">    keys and values of any of these types, or lists with elements that have</span>
+</span><span id="L-155"><a href="#L-155"><span class="linenos"> 155</span></a><span class="sd">    any of these types. These constraints are checked when setting key-value</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos"> 156</span></a><span class="sd">    pairs of the message.</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos"> 157</span></a>
+</span><span id="L-158"><a href="#L-158"><span class="linenos"> 158</span></a><span class="sd">    A message has to have a sender, which is set by the constructor:</span>
+</span><span id="L-159"><a href="#L-159"><span class="linenos"> 159</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="L-160"><a href="#L-160"><span class="linenos"> 160</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="L-161"><a href="#L-161"><span class="linenos"> 161</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;}</span>
+</span><span id="L-162"><a href="#L-162"><span class="linenos"> 162</span></a>
+</span><span id="L-163"><a href="#L-163"><span class="linenos"> 163</span></a><span class="sd">    A dictionary can be given to the constructor:</span>
+</span><span id="L-164"><a href="#L-164"><span class="linenos"> 164</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;,</span>
+</span><span id="L-165"><a href="#L-165"><span class="linenos"> 165</span></a><span class="sd">    ...             {&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})</span>
+</span><span id="L-166"><a href="#L-166"><span class="linenos"> 166</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="L-167"><a href="#L-167"><span class="linenos"> 167</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="L-168"><a href="#L-168"><span class="linenos"> 168</span></a>
+</span><span id="L-169"><a href="#L-169"><span class="linenos"> 169</span></a><span class="sd">    A &#39;sender&#39; set in the initial dictionary is overwritten by the explicitly</span>
+</span><span id="L-170"><a href="#L-170"><span class="linenos"> 170</span></a><span class="sd">    given sender in the first argument:</span>
+</span><span id="L-171"><a href="#L-171"><span class="linenos"> 171</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;,</span>
+</span><span id="L-172"><a href="#L-172"><span class="linenos"> 172</span></a><span class="sd">    ...             {&#39;sender&#39;: &#39;Original sender&#39;, &#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="L-173"><a href="#L-173"><span class="linenos"> 173</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="L-174"><a href="#L-174"><span class="linenos"> 174</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="L-175"><a href="#L-175"><span class="linenos"> 175</span></a>
+</span><span id="L-176"><a href="#L-176"><span class="linenos"> 176</span></a><span class="sd">    Or the message can be modified after construction:</span>
+</span><span id="L-177"><a href="#L-177"><span class="linenos"> 177</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})</span>
+</span><span id="L-178"><a href="#L-178"><span class="linenos"> 178</span></a><span class="sd">    &gt;&gt;&gt; m[&#39;key 2&#39;] = &#39;value 2&#39;</span>
+</span><span id="L-179"><a href="#L-179"><span class="linenos"> 179</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="L-180"><a href="#L-180"><span class="linenos"> 180</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="L-181"><a href="#L-181"><span class="linenos"> 181</span></a>
+</span><span id="L-182"><a href="#L-182"><span class="linenos"> 182</span></a><span class="sd">    The &#39;sender&#39; key can be overwritten, but this should only be done in</span>
+</span><span id="L-183"><a href="#L-183"><span class="linenos"> 183</span></a><span class="sd">    exceptional cases:</span>
+</span><span id="L-184"><a href="#L-184"><span class="linenos"> 184</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="L-185"><a href="#L-185"><span class="linenos"> 185</span></a><span class="sd">    &gt;&gt;&gt; m[&#39;sender&#39;] = &#39;New sender&#39;</span>
+</span><span id="L-186"><a href="#L-186"><span class="linenos"> 186</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="L-187"><a href="#L-187"><span class="linenos"> 187</span></a><span class="sd">    {&#39;sender&#39;: &#39;New sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="L-188"><a href="#L-188"><span class="linenos"> 188</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-189"><a href="#L-189"><span class="linenos"> 189</span></a>
+</span><span id="L-190"><a href="#L-190"><span class="linenos"> 190</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
+</span><span id="L-191"><a href="#L-191"><span class="linenos"> 191</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">sender</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">init</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MessageValue</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
+</span><span id="L-192"><a href="#L-192"><span class="linenos"> 192</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-193"><a href="#L-193"><span class="linenos"> 193</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise message.</span>
+</span><span id="L-194"><a href="#L-194"><span class="linenos"> 194</span></a>
+</span><span id="L-195"><a href="#L-195"><span class="linenos"> 195</span></a><span class="sd">        Message is initialised with given sender and possibly given</span>
+</span><span id="L-196"><a href="#L-196"><span class="linenos"> 196</span></a><span class="sd">        key-value pairs:</span>
+</span><span id="L-197"><a href="#L-197"><span class="linenos"> 197</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="L-198"><a href="#L-198"><span class="linenos"> 198</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="L-199"><a href="#L-199"><span class="linenos"> 199</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;}</span>
+</span><span id="L-200"><a href="#L-200"><span class="linenos"> 200</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})</span>
+</span><span id="L-201"><a href="#L-201"><span class="linenos"> 201</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="L-202"><a href="#L-202"><span class="linenos"> 202</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}</span>
+</span><span id="L-203"><a href="#L-203"><span class="linenos"> 203</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-204"><a href="#L-204"><span class="linenos"> 204</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="L-205"><a href="#L-205"><span class="linenos"> 205</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39; is not a valid sender name (not a string).&quot;</span><span class="p">)</span>
+</span><span id="L-206"><a href="#L-206"><span class="linenos"> 206</span></a>        <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+</span><span id="L-207"><a href="#L-207"><span class="linenos"> 207</span></a>        <span class="k">if</span> <span class="n">init</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-208"><a href="#L-208"><span class="linenos"> 208</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">init</span><span class="p">)</span>
+</span><span id="L-209"><a href="#L-209"><span class="linenos"> 209</span></a>        <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">sender</span>
+</span><span id="L-210"><a href="#L-210"><span class="linenos"> 210</span></a>
+</span><span id="L-211"><a href="#L-211"><span class="linenos"> 211</span></a>    <span class="nd">@staticmethod</span>
+</span><span id="L-212"><a href="#L-212"><span class="linenos"> 212</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="L-213"><a href="#L-213"><span class="linenos"> 213</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check recursively if a given value is valid.</span>
+</span><span id="L-214"><a href="#L-214"><span class="linenos"> 214</span></a>
+</span><span id="L-215"><a href="#L-215"><span class="linenos"> 215</span></a><span class="sd">        None, strings, integers, floats and Booleans are valid:</span>
+</span><span id="L-216"><a href="#L-216"><span class="linenos"> 216</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(None)</span>
+</span><span id="L-217"><a href="#L-217"><span class="linenos"> 217</span></a><span class="sd">        True</span>
+</span><span id="L-218"><a href="#L-218"><span class="linenos"> 218</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(&#39;Spam&#39;)</span>
+</span><span id="L-219"><a href="#L-219"><span class="linenos"> 219</span></a><span class="sd">        True</span>
+</span><span id="L-220"><a href="#L-220"><span class="linenos"> 220</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(42)</span>
+</span><span id="L-221"><a href="#L-221"><span class="linenos"> 221</span></a><span class="sd">        True</span>
+</span><span id="L-222"><a href="#L-222"><span class="linenos"> 222</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(42.42)</span>
+</span><span id="L-223"><a href="#L-223"><span class="linenos"> 223</span></a><span class="sd">        True</span>
+</span><span id="L-224"><a href="#L-224"><span class="linenos"> 224</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(False)</span>
+</span><span id="L-225"><a href="#L-225"><span class="linenos"> 225</span></a><span class="sd">        True</span>
+</span><span id="L-226"><a href="#L-226"><span class="linenos"> 226</span></a>
+</span><span id="L-227"><a href="#L-227"><span class="linenos"> 227</span></a><span class="sd">        Other basic types are not valid:</span>
+</span><span id="L-228"><a href="#L-228"><span class="linenos"> 228</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(b&#39;bytes&#39;)</span>
+</span><span id="L-229"><a href="#L-229"><span class="linenos"> 229</span></a><span class="sd">        False</span>
+</span><span id="L-230"><a href="#L-230"><span class="linenos"> 230</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(1j)</span>
+</span><span id="L-231"><a href="#L-231"><span class="linenos"> 231</span></a><span class="sd">        False</span>
+</span><span id="L-232"><a href="#L-232"><span class="linenos"> 232</span></a>
+</span><span id="L-233"><a href="#L-233"><span class="linenos"> 233</span></a><span class="sd">        Dictionaries with string keys and recursively valid values are valid:</span>
+</span><span id="L-234"><a href="#L-234"><span class="linenos"> 234</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({&#39;str value&#39;: &#39;Spam&#39;, &#39;int value&#39;: 42,</span>
+</span><span id="L-235"><a href="#L-235"><span class="linenos"> 235</span></a><span class="sd">        ...                      &#39;float value&#39;: 42.42, &#39;bool value&#39;: False})</span>
+</span><span id="L-236"><a href="#L-236"><span class="linenos"> 236</span></a><span class="sd">        True</span>
+</span><span id="L-237"><a href="#L-237"><span class="linenos"> 237</span></a>
+</span><span id="L-238"><a href="#L-238"><span class="linenos"> 238</span></a><span class="sd">        Empty dictionaries are valid:</span>
+</span><span id="L-239"><a href="#L-239"><span class="linenos"> 239</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({})</span>
+</span><span id="L-240"><a href="#L-240"><span class="linenos"> 240</span></a><span class="sd">        True</span>
+</span><span id="L-241"><a href="#L-241"><span class="linenos"> 241</span></a>
+</span><span id="L-242"><a href="#L-242"><span class="linenos"> 242</span></a><span class="sd">        Dictionaries with other keys are not valid:</span>
+</span><span id="L-243"><a href="#L-243"><span class="linenos"> 243</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({42: &#39;int key&#39;})</span>
+</span><span id="L-244"><a href="#L-244"><span class="linenos"> 244</span></a><span class="sd">        False</span>
+</span><span id="L-245"><a href="#L-245"><span class="linenos"> 245</span></a>
+</span><span id="L-246"><a href="#L-246"><span class="linenos"> 246</span></a><span class="sd">        Dictionaries with invalid values are not valid:</span>
+</span><span id="L-247"><a href="#L-247"><span class="linenos"> 247</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({&#39;complex value&#39;: 1j})</span>
+</span><span id="L-248"><a href="#L-248"><span class="linenos"> 248</span></a><span class="sd">        False</span>
+</span><span id="L-249"><a href="#L-249"><span class="linenos"> 249</span></a>
+</span><span id="L-250"><a href="#L-250"><span class="linenos"> 250</span></a><span class="sd">        Lists with valid elements are valid:</span>
+</span><span id="L-251"><a href="#L-251"><span class="linenos"> 251</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([&#39;Spam&#39;, 42, 42.42, False])</span>
+</span><span id="L-252"><a href="#L-252"><span class="linenos"> 252</span></a><span class="sd">        True</span>
+</span><span id="L-253"><a href="#L-253"><span class="linenos"> 253</span></a>
+</span><span id="L-254"><a href="#L-254"><span class="linenos"> 254</span></a><span class="sd">        Empty lists are valid:</span>
+</span><span id="L-255"><a href="#L-255"><span class="linenos"> 255</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([])</span>
+</span><span id="L-256"><a href="#L-256"><span class="linenos"> 256</span></a><span class="sd">        True</span>
+</span><span id="L-257"><a href="#L-257"><span class="linenos"> 257</span></a>
+</span><span id="L-258"><a href="#L-258"><span class="linenos"> 258</span></a><span class="sd">        Lists with invalid elements are not valid:</span>
+</span><span id="L-259"><a href="#L-259"><span class="linenos"> 259</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([1j])</span>
+</span><span id="L-260"><a href="#L-260"><span class="linenos"> 260</span></a><span class="sd">        False</span>
+</span><span id="L-261"><a href="#L-261"><span class="linenos"> 261</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-262"><a href="#L-262"><span class="linenos"> 262</span></a>        <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-263"><a href="#L-263"><span class="linenos"> 263</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-264"><a href="#L-264"><span class="linenos"> 264</span></a>        <span class="k">elif</span> <span class="p">(</span>
+</span><span id="L-265"><a href="#L-265"><span class="linenos"> 265</span></a>            <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-266"><a href="#L-266"><span class="linenos"> 266</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
+</span><span id="L-267"><a href="#L-267"><span class="linenos"> 267</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
+</span><span id="L-268"><a href="#L-268"><span class="linenos"> 268</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-269"><a href="#L-269"><span class="linenos"> 269</span></a>        <span class="p">):</span>
+</span><span id="L-270"><a href="#L-270"><span class="linenos"> 270</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-271"><a href="#L-271"><span class="linenos"> 271</span></a>        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+</span><span id="L-272"><a href="#L-272"><span class="linenos"> 272</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="L-273"><a href="#L-273"><span class="linenos"> 273</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="L-274"><a href="#L-274"><span class="linenos"> 274</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-275"><a href="#L-275"><span class="linenos"> 275</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">Message</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="L-276"><a href="#L-276"><span class="linenos"> 276</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-277"><a href="#L-277"><span class="linenos"> 277</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-278"><a href="#L-278"><span class="linenos"> 278</span></a>        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="L-279"><a href="#L-279"><span class="linenos"> 279</span></a>            <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="L-280"><a href="#L-280"><span class="linenos"> 280</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">Message</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">element</span><span class="p">):</span>
+</span><span id="L-281"><a href="#L-281"><span class="linenos"> 281</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-282"><a href="#L-282"><span class="linenos"> 282</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-283"><a href="#L-283"><span class="linenos"> 283</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-284"><a href="#L-284"><span class="linenos"> 284</span></a>
+</span><span id="L-285"><a href="#L-285"><span class="linenos"> 285</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-286"><a href="#L-286"><span class="linenos"> 286</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check key and value before putting pair into dict.</span>
+</span><span id="L-287"><a href="#L-287"><span class="linenos"> 287</span></a>
+</span><span id="L-288"><a href="#L-288"><span class="linenos"> 288</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="L-289"><a href="#L-289"><span class="linenos"> 289</span></a><span class="sd">        &gt;&gt;&gt; m[&#39;key&#39;] = &#39;value&#39;</span>
+</span><span id="L-290"><a href="#L-290"><span class="linenos"> 290</span></a><span class="sd">        &gt;&gt;&gt; m[&#39;dict&#39;] = {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}</span>
+</span><span id="L-291"><a href="#L-291"><span class="linenos"> 291</span></a><span class="sd">        &gt;&gt;&gt; print(m)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-292"><a href="#L-292"><span class="linenos"> 292</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;,</span>
+</span><span id="L-293"><a href="#L-293"><span class="linenos"> 293</span></a><span class="sd">         &#39;dict&#39;: {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}}</span>
+</span><span id="L-294"><a href="#L-294"><span class="linenos"> 294</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="L-295"><a href="#L-295"><span class="linenos"> 295</span></a><span class="sd">        &gt;&gt;&gt; m[42] = &#39;int key&#39;</span>
+</span><span id="L-296"><a href="#L-296"><span class="linenos"> 296</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-297"><a href="#L-297"><span class="linenos"> 297</span></a><span class="sd">          ...</span>
+</span><span id="L-298"><a href="#L-298"><span class="linenos"> 298</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="L-299"><a href="#L-299"><span class="linenos"> 299</span></a><span class="sd">        &gt;&gt;&gt; m[&#39;complex value&#39;] = 1j</span>
+</span><span id="L-300"><a href="#L-300"><span class="linenos"> 300</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-301"><a href="#L-301"><span class="linenos"> 301</span></a><span class="sd">          ...</span>
+</span><span id="L-302"><a href="#L-302"><span class="linenos"> 302</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="L-303"><a href="#L-303"><span class="linenos"> 303</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-304"><a href="#L-304"><span class="linenos"> 304</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="L-305"><a href="#L-305"><span class="linenos"> 305</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2">&#39; is not a valid key in Message (not a string).&quot;</span><span class="p">)</span>
+</span><span id="L-306"><a href="#L-306"><span class="linenos"> 306</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
+</span><span id="L-307"><a href="#L-307"><span class="linenos"> 307</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">&#39; is not a valid value in Message.&quot;</span><span class="p">)</span>
+</span><span id="L-308"><a href="#L-308"><span class="linenos"> 308</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+</span><span id="L-309"><a href="#L-309"><span class="linenos"> 309</span></a>
+</span><span id="L-310"><a href="#L-310"><span class="linenos"> 310</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-311"><a href="#L-311"><span class="linenos"> 311</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override update to use validity checks.</span>
+</span><span id="L-312"><a href="#L-312"><span class="linenos"> 312</span></a>
+</span><span id="L-313"><a href="#L-313"><span class="linenos"> 313</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="L-314"><a href="#L-314"><span class="linenos"> 314</span></a><span class="sd">        &gt;&gt;&gt; m.update({&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})</span>
+</span><span id="L-315"><a href="#L-315"><span class="linenos"> 315</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="L-316"><a href="#L-316"><span class="linenos"> 316</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="L-317"><a href="#L-317"><span class="linenos"> 317</span></a><span class="sd">        &gt;&gt;&gt; m.update({42: &#39;int key&#39;})</span>
+</span><span id="L-318"><a href="#L-318"><span class="linenos"> 318</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-319"><a href="#L-319"><span class="linenos"> 319</span></a><span class="sd">          ...</span>
+</span><span id="L-320"><a href="#L-320"><span class="linenos"> 320</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="L-321"><a href="#L-321"><span class="linenos"> 321</span></a><span class="sd">        &gt;&gt;&gt; m.update({&#39;complex value&#39;: 1j})</span>
+</span><span id="L-322"><a href="#L-322"><span class="linenos"> 322</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-323"><a href="#L-323"><span class="linenos"> 323</span></a><span class="sd">          ...</span>
+</span><span id="L-324"><a href="#L-324"><span class="linenos"> 324</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="L-325"><a href="#L-325"><span class="linenos"> 325</span></a>
+</span><span id="L-326"><a href="#L-326"><span class="linenos"> 326</span></a><span class="sd">        This is also used in __init__:</span>
+</span><span id="L-327"><a href="#L-327"><span class="linenos"> 327</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="L-328"><a href="#L-328"><span class="linenos"> 328</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="L-329"><a href="#L-329"><span class="linenos"> 329</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="L-330"><a href="#L-330"><span class="linenos"> 330</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {42: &#39;int key&#39;})</span>
+</span><span id="L-331"><a href="#L-331"><span class="linenos"> 331</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-332"><a href="#L-332"><span class="linenos"> 332</span></a><span class="sd">          ...</span>
+</span><span id="L-333"><a href="#L-333"><span class="linenos"> 333</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="L-334"><a href="#L-334"><span class="linenos"> 334</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;complex value&#39;: 1j})</span>
+</span><span id="L-335"><a href="#L-335"><span class="linenos"> 335</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-336"><a href="#L-336"><span class="linenos"> 336</span></a><span class="sd">          ...</span>
+</span><span id="L-337"><a href="#L-337"><span class="linenos"> 337</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="L-338"><a href="#L-338"><span class="linenos"> 338</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-339"><a href="#L-339"><span class="linenos"> 339</span></a>        <span class="k">if</span> <span class="n">args</span><span class="p">:</span>
+</span><span id="L-340"><a href="#L-340"><span class="linenos"> 340</span></a>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+</span><span id="L-341"><a href="#L-341"><span class="linenos"> 341</span></a>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;update expected at most 1 argument, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="L-342"><a href="#L-342"><span class="linenos"> 342</span></a>            <span class="n">other</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</span><span id="L-343"><a href="#L-343"><span class="linenos"> 343</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">other</span><span class="p">:</span>
+</span><span id="L-344"><a href="#L-344"><span class="linenos"> 344</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">other</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-345"><a href="#L-345"><span class="linenos"> 345</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
+</span><span id="L-346"><a href="#L-346"><span class="linenos"> 346</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-347"><a href="#L-347"><span class="linenos"> 347</span></a>
+</span><span id="L-348"><a href="#L-348"><span class="linenos"> 348</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MessageValue</span><span class="p">:</span>
+</span><span id="L-349"><a href="#L-349"><span class="linenos"> 349</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override setdefault to use validity checks.</span>
+</span><span id="L-350"><a href="#L-350"><span class="linenos"> 350</span></a>
+</span><span id="L-351"><a href="#L-351"><span class="linenos"> 351</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="L-352"><a href="#L-352"><span class="linenos"> 352</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 1&#39;)</span>
+</span><span id="L-353"><a href="#L-353"><span class="linenos"> 353</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="L-354"><a href="#L-354"><span class="linenos"> 354</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 2&#39;)</span>
+</span><span id="L-355"><a href="#L-355"><span class="linenos"> 355</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="L-356"><a href="#L-356"><span class="linenos"> 356</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(42, &#39;int key&#39;)</span>
+</span><span id="L-357"><a href="#L-357"><span class="linenos"> 357</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-358"><a href="#L-358"><span class="linenos"> 358</span></a><span class="sd">          ...</span>
+</span><span id="L-359"><a href="#L-359"><span class="linenos"> 359</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="L-360"><a href="#L-360"><span class="linenos"> 360</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;complex value&#39;, 1j)</span>
+</span><span id="L-361"><a href="#L-361"><span class="linenos"> 361</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-362"><a href="#L-362"><span class="linenos"> 362</span></a><span class="sd">          ...</span>
+</span><span id="L-363"><a href="#L-363"><span class="linenos"> 363</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="L-364"><a href="#L-364"><span class="linenos"> 364</span></a>
+</span><span id="L-365"><a href="#L-365"><span class="linenos"> 365</span></a><span class="sd">        But __setitem__ is not called if the key is already present:</span>
+</span><span id="L-366"><a href="#L-366"><span class="linenos"> 366</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, 1j)</span>
+</span><span id="L-367"><a href="#L-367"><span class="linenos"> 367</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="L-368"><a href="#L-368"><span class="linenos"> 368</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-369"><a href="#L-369"><span class="linenos"> 369</span></a>        <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="L-370"><a href="#L-370"><span class="linenos"> 370</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="L-371"><a href="#L-371"><span class="linenos"> 371</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-372"><a href="#L-372"><span class="linenos"> 372</span></a>
+</span><span id="L-373"><a href="#L-373"><span class="linenos"> 373</span></a>
+</span><span id="L-374"><a href="#L-374"><span class="linenos"> 374</span></a><span class="k">class</span><span class="w"> </span><span class="nc">MessageTemplate</span><span class="p">(</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">JSONSchema</span><span class="p">]):</span>
+</span><span id="L-375"><a href="#L-375"><span class="linenos"> 375</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define a message template.</span>
+</span><span id="L-376"><a href="#L-376"><span class="linenos"> 376</span></a>
+</span><span id="L-377"><a href="#L-377"><span class="linenos"> 377</span></a><span class="sd">    A message template is a mapping from string keys to JSON schemas as</span>
+</span><span id="L-378"><a href="#L-378"><span class="linenos"> 378</span></a><span class="sd">    values:</span>
+</span><span id="L-379"><a href="#L-379"><span class="linenos"> 379</span></a><span class="sd">    &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="L-380"><a href="#L-380"><span class="linenos"> 380</span></a><span class="sd">    ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;}})</span>
+</span><span id="L-381"><a href="#L-381"><span class="linenos"> 381</span></a><span class="sd">    &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-382"><a href="#L-382"><span class="linenos"> 382</span></a><span class="sd">    ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-383"><a href="#L-383"><span class="linenos"> 383</span></a><span class="sd">    ...                              &#39;key 2&#39;: True}}</span>
+</span><span id="L-384"><a href="#L-384"><span class="linenos"> 384</span></a>
+</span><span id="L-385"><a href="#L-385"><span class="linenos"> 385</span></a><span class="sd">    A message template matches a message if all keys of the template are</span>
+</span><span id="L-386"><a href="#L-386"><span class="linenos"> 386</span></a><span class="sd">    contained in the message and the values in the message validate against</span>
+</span><span id="L-387"><a href="#L-387"><span class="linenos"> 387</span></a><span class="sd">    the respective schemas:</span>
+</span><span id="L-388"><a href="#L-388"><span class="linenos"> 388</span></a><span class="sd">    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="L-389"><a href="#L-389"><span class="linenos"> 389</span></a><span class="sd">    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="L-390"><a href="#L-390"><span class="linenos"> 390</span></a><span class="sd">    ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42, &#39;key 2&#39;: None}}))</span>
+</span><span id="L-391"><a href="#L-391"><span class="linenos"> 391</span></a><span class="sd">    True</span>
+</span><span id="L-392"><a href="#L-392"><span class="linenos"> 392</span></a>
+</span><span id="L-393"><a href="#L-393"><span class="linenos"> 393</span></a><span class="sd">    An empty mapping therefore matches all messages:</span>
+</span><span id="L-394"><a href="#L-394"><span class="linenos"> 394</span></a><span class="sd">    &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="L-395"><a href="#L-395"><span class="linenos"> 395</span></a><span class="sd">    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;arbitrary&#39;: &#39;content&#39;}))</span>
+</span><span id="L-396"><a href="#L-396"><span class="linenos"> 396</span></a><span class="sd">    True</span>
+</span><span id="L-397"><a href="#L-397"><span class="linenos"> 397</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-398"><a href="#L-398"><span class="linenos"> 398</span></a>
+</span><span id="L-399"><a href="#L-399"><span class="linenos"> 399</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">init</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">JSONSchema</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-400"><a href="#L-400"><span class="linenos"> 400</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise message.</span>
+</span><span id="L-401"><a href="#L-401"><span class="linenos"> 401</span></a>
+</span><span id="L-402"><a href="#L-402"><span class="linenos"> 402</span></a><span class="sd">        Template is initialised empty or with given key-value pairs:</span>
+</span><span id="L-403"><a href="#L-403"><span class="linenos"> 403</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="L-404"><a href="#L-404"><span class="linenos"> 404</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="L-405"><a href="#L-405"><span class="linenos"> 405</span></a><span class="sd">        {}</span>
+</span><span id="L-406"><a href="#L-406"><span class="linenos"> 406</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})</span>
+</span><span id="L-407"><a href="#L-407"><span class="linenos"> 407</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="L-408"><a href="#L-408"><span class="linenos"> 408</span></a><span class="sd">        {&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</span><span id="L-409"><a href="#L-409"><span class="linenos"> 409</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-410"><a href="#L-410"><span class="linenos"> 410</span></a>        <span class="k">if</span> <span class="n">init</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-411"><a href="#L-411"><span class="linenos"> 411</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">init</span><span class="p">)</span>
+</span><span id="L-412"><a href="#L-412"><span class="linenos"> 412</span></a>
+</span><span id="L-413"><a href="#L-413"><span class="linenos"> 413</span></a>    <span class="nd">@staticmethod</span>
+</span><span id="L-414"><a href="#L-414"><span class="linenos"> 414</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">from_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;MessageTemplate&quot;</span><span class="p">:</span>
+</span><span id="L-415"><a href="#L-415"><span class="linenos"> 415</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Create template from message.</span>
+</span><span id="L-416"><a href="#L-416"><span class="linenos"> 416</span></a>
+</span><span id="L-417"><a href="#L-417"><span class="linenos"> 417</span></a><span class="sd">        Template witch constant schemas is created from message:</span>
+</span><span id="L-418"><a href="#L-418"><span class="linenos"> 418</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="L-419"><a href="#L-419"><span class="linenos"> 419</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="L-420"><a href="#L-420"><span class="linenos"> 420</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="L-421"><a href="#L-421"><span class="linenos"> 421</span></a><span class="sd">        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</span><span id="L-422"><a href="#L-422"><span class="linenos"> 422</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},</span>
+</span><span id="L-423"><a href="#L-423"><span class="linenos"> 423</span></a><span class="sd">        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})</span>
+</span><span id="L-424"><a href="#L-424"><span class="linenos"> 424</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="L-425"><a href="#L-425"><span class="linenos"> 425</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-426"><a href="#L-426"><span class="linenos"> 426</span></a><span class="sd">        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},</span>
+</span><span id="L-427"><a href="#L-427"><span class="linenos"> 427</span></a><span class="sd">         &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-428"><a href="#L-428"><span class="linenos"> 428</span></a><span class="sd">                  &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="L-429"><a href="#L-429"><span class="linenos"> 429</span></a><span class="sd">                                 &#39;float&#39;: {&#39;const&#39;: 42.42}}},</span>
+</span><span id="L-430"><a href="#L-430"><span class="linenos"> 430</span></a><span class="sd">         &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+</span><span id="L-431"><a href="#L-431"><span class="linenos"> 431</span></a><span class="sd">                  &#39;items&#39;: [{&#39;const&#39;: None},</span>
+</span><span id="L-432"><a href="#L-432"><span class="linenos"> 432</span></a><span class="sd">                            {&#39;const&#39;: True},</span>
+</span><span id="L-433"><a href="#L-433"><span class="linenos"> 433</span></a><span class="sd">                            {&#39;const&#39;: &#39;string&#39;}]}}</span>
+</span><span id="L-434"><a href="#L-434"><span class="linenos"> 434</span></a>
+</span><span id="L-435"><a href="#L-435"><span class="linenos"> 435</span></a><span class="sd">        This is especially useful for clients that send certain fully</span>
+</span><span id="L-436"><a href="#L-436"><span class="linenos"> 436</span></a><span class="sd">        predefined messages, where the message is given in the configuration</span>
+</span><span id="L-437"><a href="#L-437"><span class="linenos"> 437</span></a><span class="sd">        and the template for the registration can be constructed by this</span>
+</span><span id="L-438"><a href="#L-438"><span class="linenos"> 438</span></a><span class="sd">        method.</span>
+</span><span id="L-439"><a href="#L-439"><span class="linenos"> 439</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-440"><a href="#L-440"><span class="linenos"> 440</span></a>
+</span><span id="L-441"><a href="#L-441"><span class="linenos"> 441</span></a>        <span class="k">def</span><span class="w"> </span><span class="nf">schema_from_value</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">JSONSchema</span><span class="p">:</span>
+</span><span id="L-442"><a href="#L-442"><span class="linenos"> 442</span></a>            <span class="n">schema</span><span class="p">:</span> <span class="n">JSONSchema</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-443"><a href="#L-443"><span class="linenos"> 443</span></a>            <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-444"><a href="#L-444"><span class="linenos"> 444</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span>
+</span><span id="L-445"><a href="#L-445"><span class="linenos"> 445</span></a>            <span class="k">elif</span> <span class="p">(</span>
+</span><span id="L-446"><a href="#L-446"><span class="linenos"> 446</span></a>                <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-447"><a href="#L-447"><span class="linenos"> 447</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
+</span><span id="L-448"><a href="#L-448"><span class="linenos"> 448</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
+</span><span id="L-449"><a href="#L-449"><span class="linenos"> 449</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-450"><a href="#L-450"><span class="linenos"> 450</span></a>            <span class="p">):</span>
+</span><span id="L-451"><a href="#L-451"><span class="linenos"> 451</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">value</span><span class="p">}</span>
+</span><span id="L-452"><a href="#L-452"><span class="linenos"> 452</span></a>            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+</span><span id="L-453"><a href="#L-453"><span class="linenos"> 453</span></a>                <span class="n">properties</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-454"><a href="#L-454"><span class="linenos"> 454</span></a>                <span class="k">for</span> <span class="n">inner_key</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="L-455"><a href="#L-455"><span class="linenos"> 455</span></a>                    <span class="n">inner_value</span><span class="p">:</span> <span class="n">Message</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="n">inner_key</span><span class="p">]</span>
+</span><span id="L-456"><a href="#L-456"><span class="linenos"> 456</span></a>                    <span class="n">properties</span><span class="p">[</span><span class="n">inner_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">schema_from_value</span><span class="p">(</span><span class="n">inner_value</span><span class="p">)</span>
+</span><span id="L-457"><a href="#L-457"><span class="linenos"> 457</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">,</span> <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="n">properties</span><span class="p">}</span>
+</span><span id="L-458"><a href="#L-458"><span class="linenos"> 458</span></a>            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="L-459"><a href="#L-459"><span class="linenos"> 459</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-460"><a href="#L-460"><span class="linenos"> 460</span></a>                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="L-461"><a href="#L-461"><span class="linenos"> 461</span></a>                    <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">schema_from_value</span><span class="p">(</span><span class="n">element</span><span class="p">)</span> <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">value</span><span class="p">],</span>
+</span><span id="L-462"><a href="#L-462"><span class="linenos"> 462</span></a>                <span class="p">}</span>
+</span><span id="L-463"><a href="#L-463"><span class="linenos"> 463</span></a>            <span class="k">return</span> <span class="n">schema</span>
+</span><span id="L-464"><a href="#L-464"><span class="linenos"> 464</span></a>
+</span><span id="L-465"><a href="#L-465"><span class="linenos"> 465</span></a>        <span class="n">template</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+</span><span id="L-466"><a href="#L-466"><span class="linenos"> 466</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-467"><a href="#L-467"><span class="linenos"> 467</span></a>            <span class="n">template</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">schema_from_value</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
+</span><span id="L-468"><a href="#L-468"><span class="linenos"> 468</span></a>        <span class="k">return</span> <span class="n">template</span>
+</span><span id="L-469"><a href="#L-469"><span class="linenos"> 469</span></a>
+</span><span id="L-470"><a href="#L-470"><span class="linenos"> 470</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">JSONSchema</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-471"><a href="#L-471"><span class="linenos"> 471</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check key and value before putting pair into dict.</span>
+</span><span id="L-472"><a href="#L-472"><span class="linenos"> 472</span></a>
+</span><span id="L-473"><a href="#L-473"><span class="linenos"> 473</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="L-474"><a href="#L-474"><span class="linenos"> 474</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key 1&#39;] = {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="L-475"><a href="#L-475"><span class="linenos"> 475</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key 2&#39;] = {&#39;type&#39;: &#39;string&#39;}</span>
+</span><span id="L-476"><a href="#L-476"><span class="linenos"> 476</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-477"><a href="#L-477"><span class="linenos"> 477</span></a><span class="sd">        ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-478"><a href="#L-478"><span class="linenos"> 478</span></a><span class="sd">        ...                              &#39;key 2&#39;: True}}</span>
+</span><span id="L-479"><a href="#L-479"><span class="linenos"> 479</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-480"><a href="#L-480"><span class="linenos"> 480</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="L-481"><a href="#L-481"><span class="linenos"> 481</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-482"><a href="#L-482"><span class="linenos"> 482</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-483"><a href="#L-483"><span class="linenos"> 483</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="L-484"><a href="#L-484"><span class="linenos"> 484</span></a><span class="sd">        &gt;&gt;&gt; t[42] = {&#39;const&#39;: &#39;int key&#39;}</span>
+</span><span id="L-485"><a href="#L-485"><span class="linenos"> 485</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-486"><a href="#L-486"><span class="linenos"> 486</span></a><span class="sd">          ...</span>
+</span><span id="L-487"><a href="#L-487"><span class="linenos"> 487</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="L-488"><a href="#L-488"><span class="linenos"> 488</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key&#39;] = &#39;schema&#39;  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-489"><a href="#L-489"><span class="linenos"> 489</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-490"><a href="#L-490"><span class="linenos"> 490</span></a><span class="sd">          ...</span>
+</span><span id="L-491"><a href="#L-491"><span class="linenos"> 491</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="L-492"><a href="#L-492"><span class="linenos"> 492</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="L-493"><a href="#L-493"><span class="linenos"> 493</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key&#39;] = True</span>
+</span><span id="L-494"><a href="#L-494"><span class="linenos"> 494</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-495"><a href="#L-495"><span class="linenos"> 495</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="L-496"><a href="#L-496"><span class="linenos"> 496</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span>
+</span><span id="L-497"><a href="#L-497"><span class="linenos"> 497</span></a>                <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2">&#39; is not a valid key in MessageTemplate (not a string).&quot;</span>
+</span><span id="L-498"><a href="#L-498"><span class="linenos"> 498</span></a>            <span class="p">)</span>
+</span><span id="L-499"><a href="#L-499"><span class="linenos"> 499</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">register_schema</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
+</span><span id="L-500"><a href="#L-500"><span class="linenos"> 500</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span>
+</span><span id="L-501"><a href="#L-501"><span class="linenos"> 501</span></a>                <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">&#39; is not a valid value in&quot;</span>
+</span><span id="L-502"><a href="#L-502"><span class="linenos"> 502</span></a>                <span class="s2">&quot; MessageTemplate (not a valid JSON schema).&quot;</span>
+</span><span id="L-503"><a href="#L-503"><span class="linenos"> 503</span></a>            <span class="p">)</span>
+</span><span id="L-504"><a href="#L-504"><span class="linenos"> 504</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+</span><span id="L-505"><a href="#L-505"><span class="linenos"> 505</span></a>
+</span><span id="L-506"><a href="#L-506"><span class="linenos"> 506</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-507"><a href="#L-507"><span class="linenos"> 507</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override update to use validity checks.</span>
+</span><span id="L-508"><a href="#L-508"><span class="linenos"> 508</span></a>
+</span><span id="L-509"><a href="#L-509"><span class="linenos"> 509</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="L-510"><a href="#L-510"><span class="linenos"> 510</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="L-511"><a href="#L-511"><span class="linenos"> 511</span></a><span class="sd">        ...           &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="L-512"><a href="#L-512"><span class="linenos"> 512</span></a><span class="sd">        ...           &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-513"><a href="#L-513"><span class="linenos"> 513</span></a><span class="sd">        ...                     &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-514"><a href="#L-514"><span class="linenos"> 514</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True}}})</span>
+</span><span id="L-515"><a href="#L-515"><span class="linenos"> 515</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-516"><a href="#L-516"><span class="linenos"> 516</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="L-517"><a href="#L-517"><span class="linenos"> 517</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-518"><a href="#L-518"><span class="linenos"> 518</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-519"><a href="#L-519"><span class="linenos"> 519</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="L-520"><a href="#L-520"><span class="linenos"> 520</span></a><span class="sd">        &gt;&gt;&gt; t.update({42: {&#39;const&#39;: &#39;int key&#39;}})</span>
+</span><span id="L-521"><a href="#L-521"><span class="linenos"> 521</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-522"><a href="#L-522"><span class="linenos"> 522</span></a><span class="sd">          ...</span>
+</span><span id="L-523"><a href="#L-523"><span class="linenos"> 523</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="L-524"><a href="#L-524"><span class="linenos"> 524</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key&#39;: &#39;schema&#39;})  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-525"><a href="#L-525"><span class="linenos"> 525</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-526"><a href="#L-526"><span class="linenos"> 526</span></a><span class="sd">          ...</span>
+</span><span id="L-527"><a href="#L-527"><span class="linenos"> 527</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="L-528"><a href="#L-528"><span class="linenos"> 528</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="L-529"><a href="#L-529"><span class="linenos"> 529</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key&#39;: True})</span>
+</span><span id="L-530"><a href="#L-530"><span class="linenos"> 530</span></a>
+</span><span id="L-531"><a href="#L-531"><span class="linenos"> 531</span></a><span class="sd">        This is also used in __init__:</span>
+</span><span id="L-532"><a href="#L-532"><span class="linenos"> 532</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="L-533"><a href="#L-533"><span class="linenos"> 533</span></a><span class="sd">        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="L-534"><a href="#L-534"><span class="linenos"> 534</span></a><span class="sd">        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-535"><a href="#L-535"><span class="linenos"> 535</span></a><span class="sd">        ...                                &#39;properties&#39;: {</span>
+</span><span id="L-536"><a href="#L-536"><span class="linenos"> 536</span></a><span class="sd">        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-537"><a href="#L-537"><span class="linenos"> 537</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True}}})</span>
+</span><span id="L-538"><a href="#L-538"><span class="linenos"> 538</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-539"><a href="#L-539"><span class="linenos"> 539</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="L-540"><a href="#L-540"><span class="linenos"> 540</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-541"><a href="#L-541"><span class="linenos"> 541</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-542"><a href="#L-542"><span class="linenos"> 542</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="L-543"><a href="#L-543"><span class="linenos"> 543</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({42: {&#39;const&#39;: &#39;int key&#39;}})</span>
+</span><span id="L-544"><a href="#L-544"><span class="linenos"> 544</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-545"><a href="#L-545"><span class="linenos"> 545</span></a><span class="sd">          ...</span>
+</span><span id="L-546"><a href="#L-546"><span class="linenos"> 546</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="L-547"><a href="#L-547"><span class="linenos"> 547</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: &#39;schema&#39;})</span>
+</span><span id="L-548"><a href="#L-548"><span class="linenos"> 548</span></a><span class="sd">        ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-549"><a href="#L-549"><span class="linenos"> 549</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-550"><a href="#L-550"><span class="linenos"> 550</span></a><span class="sd">          ...</span>
+</span><span id="L-551"><a href="#L-551"><span class="linenos"> 551</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="L-552"><a href="#L-552"><span class="linenos"> 552</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="L-553"><a href="#L-553"><span class="linenos"> 553</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: True})</span>
+</span><span id="L-554"><a href="#L-554"><span class="linenos"> 554</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-555"><a href="#L-555"><span class="linenos"> 555</span></a>        <span class="k">if</span> <span class="n">args</span><span class="p">:</span>
+</span><span id="L-556"><a href="#L-556"><span class="linenos"> 556</span></a>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+</span><span id="L-557"><a href="#L-557"><span class="linenos"> 557</span></a>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;update expected at most 1 argument, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="L-558"><a href="#L-558"><span class="linenos"> 558</span></a>            <span class="n">other</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</span><span id="L-559"><a href="#L-559"><span class="linenos"> 559</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">other</span><span class="p">:</span>
+</span><span id="L-560"><a href="#L-560"><span class="linenos"> 560</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">other</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-561"><a href="#L-561"><span class="linenos"> 561</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
+</span><span id="L-562"><a href="#L-562"><span class="linenos"> 562</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-563"><a href="#L-563"><span class="linenos"> 563</span></a>
+</span><span id="L-564"><a href="#L-564"><span class="linenos"> 564</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">JSONSchema</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">JSONSchema</span><span class="p">:</span>
+</span><span id="L-565"><a href="#L-565"><span class="linenos"> 565</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override setdefault to use validity checks.</span>
+</span><span id="L-566"><a href="#L-566"><span class="linenos"> 566</span></a>
+</span><span id="L-567"><a href="#L-567"><span class="linenos"> 567</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="L-568"><a href="#L-568"><span class="linenos"> 568</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, {&#39;const&#39;: &#39;value&#39;})</span>
+</span><span id="L-569"><a href="#L-569"><span class="linenos"> 569</span></a><span class="sd">        {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="L-570"><a href="#L-570"><span class="linenos"> 570</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 2&#39;, {&#39;type&#39;: &#39;string&#39;})</span>
+</span><span id="L-571"><a href="#L-571"><span class="linenos"> 571</span></a><span class="sd">        {&#39;type&#39;: &#39;string&#39;}</span>
+</span><span id="L-572"><a href="#L-572"><span class="linenos"> 572</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 3&#39;, {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-573"><a href="#L-573"><span class="linenos"> 573</span></a><span class="sd">        ...                        &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-574"><a href="#L-574"><span class="linenos"> 574</span></a><span class="sd">        ...                                       &#39;key 2&#39;: True}})</span>
+</span><span id="L-575"><a href="#L-575"><span class="linenos"> 575</span></a><span class="sd">        ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-576"><a href="#L-576"><span class="linenos"> 576</span></a><span class="sd">        {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-577"><a href="#L-577"><span class="linenos"> 577</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-578"><a href="#L-578"><span class="linenos"> 578</span></a><span class="sd">                                  &#39;key 2&#39;: True}}</span>
+</span><span id="L-579"><a href="#L-579"><span class="linenos"> 579</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(42, {&#39;const&#39;: &#39;int key&#39;})</span>
+</span><span id="L-580"><a href="#L-580"><span class="linenos"> 580</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-581"><a href="#L-581"><span class="linenos"> 581</span></a><span class="sd">          ...</span>
+</span><span id="L-582"><a href="#L-582"><span class="linenos"> 582</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="L-583"><a href="#L-583"><span class="linenos"> 583</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key&#39;, &#39;schema&#39;)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-584"><a href="#L-584"><span class="linenos"> 584</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="L-585"><a href="#L-585"><span class="linenos"> 585</span></a><span class="sd">          ...</span>
+</span><span id="L-586"><a href="#L-586"><span class="linenos"> 586</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="L-587"><a href="#L-587"><span class="linenos"> 587</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="L-588"><a href="#L-588"><span class="linenos"> 588</span></a>
+</span><span id="L-589"><a href="#L-589"><span class="linenos"> 589</span></a><span class="sd">        But __setitem__ is not called if the key is already present:</span>
+</span><span id="L-590"><a href="#L-590"><span class="linenos"> 590</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, &#39;schema&#39;)</span>
+</span><span id="L-591"><a href="#L-591"><span class="linenos"> 591</span></a><span class="sd">        {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="L-592"><a href="#L-592"><span class="linenos"> 592</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-593"><a href="#L-593"><span class="linenos"> 593</span></a>        <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="L-594"><a href="#L-594"><span class="linenos"> 594</span></a>            <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-595"><a href="#L-595"><span class="linenos"> 595</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="L-596"><a href="#L-596"><span class="linenos"> 596</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="L-597"><a href="#L-597"><span class="linenos"> 597</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="L-598"><a href="#L-598"><span class="linenos"> 598</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-599"><a href="#L-599"><span class="linenos"> 599</span></a>
+</span><span id="L-600"><a href="#L-600"><span class="linenos"> 600</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="L-601"><a href="#L-601"><span class="linenos"> 601</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check message against this template.</span>
+</span><span id="L-602"><a href="#L-602"><span class="linenos"> 602</span></a>
+</span><span id="L-603"><a href="#L-603"><span class="linenos"> 603</span></a><span class="sd">        Constant values have to match exactly:</span>
+</span><span id="L-604"><a href="#L-604"><span class="linenos"> 604</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})</span>
+</span><span id="L-605"><a href="#L-605"><span class="linenos"> 605</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;}))</span>
+</span><span id="L-606"><a href="#L-606"><span class="linenos"> 606</span></a><span class="sd">        True</span>
+</span><span id="L-607"><a href="#L-607"><span class="linenos"> 607</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;other value&#39;}))</span>
+</span><span id="L-608"><a href="#L-608"><span class="linenos"> 608</span></a><span class="sd">        False</span>
+</span><span id="L-609"><a href="#L-609"><span class="linenos"> 609</span></a>
+</span><span id="L-610"><a href="#L-610"><span class="linenos"> 610</span></a><span class="sd">        But for integers, floats with the same value are also valid:</span>
+</span><span id="L-611"><a href="#L-611"><span class="linenos"> 611</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: 42}})</span>
+</span><span id="L-612"><a href="#L-612"><span class="linenos"> 612</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="L-613"><a href="#L-613"><span class="linenos"> 613</span></a><span class="sd">        True</span>
+</span><span id="L-614"><a href="#L-614"><span class="linenos"> 614</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))</span>
+</span><span id="L-615"><a href="#L-615"><span class="linenos"> 615</span></a><span class="sd">        True</span>
+</span><span id="L-616"><a href="#L-616"><span class="linenos"> 616</span></a>
+</span><span id="L-617"><a href="#L-617"><span class="linenos"> 617</span></a><span class="sd">        Type integer is valid for floats with zero fractional part, but</span>
+</span><span id="L-618"><a href="#L-618"><span class="linenos"> 618</span></a><span class="sd">        not by floats with non-zero fractional part:</span>
+</span><span id="L-619"><a href="#L-619"><span class="linenos"> 619</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;integer&#39;}})</span>
+</span><span id="L-620"><a href="#L-620"><span class="linenos"> 620</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="L-621"><a href="#L-621"><span class="linenos"> 621</span></a><span class="sd">        True</span>
+</span><span id="L-622"><a href="#L-622"><span class="linenos"> 622</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))</span>
+</span><span id="L-623"><a href="#L-623"><span class="linenos"> 623</span></a><span class="sd">        True</span>
+</span><span id="L-624"><a href="#L-624"><span class="linenos"> 624</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))</span>
+</span><span id="L-625"><a href="#L-625"><span class="linenos"> 625</span></a><span class="sd">        False</span>
+</span><span id="L-626"><a href="#L-626"><span class="linenos"> 626</span></a>
+</span><span id="L-627"><a href="#L-627"><span class="linenos"> 627</span></a><span class="sd">        Type number is valid for arbitrary ints or floats:</span>
+</span><span id="L-628"><a href="#L-628"><span class="linenos"> 628</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;number&#39;}})</span>
+</span><span id="L-629"><a href="#L-629"><span class="linenos"> 629</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="L-630"><a href="#L-630"><span class="linenos"> 630</span></a><span class="sd">        True</span>
+</span><span id="L-631"><a href="#L-631"><span class="linenos"> 631</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))</span>
+</span><span id="L-632"><a href="#L-632"><span class="linenos"> 632</span></a><span class="sd">        True</span>
+</span><span id="L-633"><a href="#L-633"><span class="linenos"> 633</span></a>
+</span><span id="L-634"><a href="#L-634"><span class="linenos"> 634</span></a><span class="sd">        All keys in template have to be present in message:</span>
+</span><span id="L-635"><a href="#L-635"><span class="linenos"> 635</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="L-636"><a href="#L-636"><span class="linenos"> 636</span></a><span class="sd">        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="L-637"><a href="#L-637"><span class="linenos"> 637</span></a><span class="sd">        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="L-638"><a href="#L-638"><span class="linenos"> 638</span></a><span class="sd">        ...                                &#39;properties&#39;: {</span>
+</span><span id="L-639"><a href="#L-639"><span class="linenos"> 639</span></a><span class="sd">        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-640"><a href="#L-640"><span class="linenos"> 640</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True,</span>
+</span><span id="L-641"><a href="#L-641"><span class="linenos"> 641</span></a><span class="sd">        ...                                    &#39;key 3&#39;: False}}})</span>
+</span><span id="L-642"><a href="#L-642"><span class="linenos"> 642</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="L-643"><a href="#L-643"><span class="linenos"> 643</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;}))</span>
+</span><span id="L-644"><a href="#L-644"><span class="linenos"> 644</span></a><span class="sd">        False</span>
+</span><span id="L-645"><a href="#L-645"><span class="linenos"> 645</span></a>
+</span><span id="L-646"><a href="#L-646"><span class="linenos"> 646</span></a><span class="sd">        But for nested objects their properties do not necessarily have</span>
+</span><span id="L-647"><a href="#L-647"><span class="linenos"> 647</span></a><span class="sd">        to be present:</span>
+</span><span id="L-648"><a href="#L-648"><span class="linenos"> 648</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="L-649"><a href="#L-649"><span class="linenos"> 649</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="L-650"><a href="#L-650"><span class="linenos"> 650</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42}}))</span>
+</span><span id="L-651"><a href="#L-651"><span class="linenos"> 651</span></a><span class="sd">        True</span>
+</span><span id="L-652"><a href="#L-652"><span class="linenos"> 652</span></a>
+</span><span id="L-653"><a href="#L-653"><span class="linenos"> 653</span></a><span class="sd">        Schema True matches everything (even None):</span>
+</span><span id="L-654"><a href="#L-654"><span class="linenos"> 654</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="L-655"><a href="#L-655"><span class="linenos"> 655</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="L-656"><a href="#L-656"><span class="linenos"> 656</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 2&#39;: None}}))</span>
+</span><span id="L-657"><a href="#L-657"><span class="linenos"> 657</span></a><span class="sd">        True</span>
+</span><span id="L-658"><a href="#L-658"><span class="linenos"> 658</span></a>
+</span><span id="L-659"><a href="#L-659"><span class="linenos"> 659</span></a><span class="sd">        Schema False matches nothing:</span>
+</span><span id="L-660"><a href="#L-660"><span class="linenos"> 660</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="L-661"><a href="#L-661"><span class="linenos"> 661</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="L-662"><a href="#L-662"><span class="linenos"> 662</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 3&#39;: True}}))</span>
+</span><span id="L-663"><a href="#L-663"><span class="linenos"> 663</span></a><span class="sd">        False</span>
+</span><span id="L-664"><a href="#L-664"><span class="linenos"> 664</span></a>
+</span><span id="L-665"><a href="#L-665"><span class="linenos"> 665</span></a><span class="sd">        Message is valid for the constant template created from it:</span>
+</span><span id="L-666"><a href="#L-666"><span class="linenos"> 666</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},</span>
+</span><span id="L-667"><a href="#L-667"><span class="linenos"> 667</span></a><span class="sd">        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})</span>
+</span><span id="L-668"><a href="#L-668"><span class="linenos"> 668</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="L-669"><a href="#L-669"><span class="linenos"> 669</span></a><span class="sd">        &gt;&gt;&gt; t.check(m)</span>
+</span><span id="L-670"><a href="#L-670"><span class="linenos"> 670</span></a><span class="sd">        True</span>
+</span><span id="L-671"><a href="#L-671"><span class="linenos"> 671</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-672"><a href="#L-672"><span class="linenos"> 672</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="L-673"><a href="#L-673"><span class="linenos"> 673</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-674"><a href="#L-674"><span class="linenos"> 674</span></a>                <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-675"><a href="#L-675"><span class="linenos"> 675</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="L-676"><a href="#L-676"><span class="linenos"> 676</span></a>                <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
+</span><span id="L-677"><a href="#L-677"><span class="linenos"> 677</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="L-678"><a href="#L-678"><span class="linenos"> 678</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-679"><a href="#L-679"><span class="linenos"> 679</span></a>        <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-680"><a href="#L-680"><span class="linenos"> 680</span></a>
+</span><span id="L-681"><a href="#L-681"><span class="linenos"> 681</span></a>
+</span><span id="L-682"><a href="#L-682"><span class="linenos"> 682</span></a><span class="k">class</span><span class="w"> </span><span class="nc">TemplateRegistry</span><span class="p">:</span>
+</span><span id="L-683"><a href="#L-683"><span class="linenos"> 683</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Manage a collection of message templates with registered clients.</span>
+</span><span id="L-684"><a href="#L-684"><span class="linenos"> 684</span></a>
+</span><span id="L-685"><a href="#L-685"><span class="linenos"> 685</span></a><span class="sd">    A new TemplateRegistry is created by:</span>
+</span><span id="L-686"><a href="#L-686"><span class="linenos"> 686</span></a><span class="sd">    &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-687"><a href="#L-687"><span class="linenos"> 687</span></a>
+</span><span id="L-688"><a href="#L-688"><span class="linenos"> 688</span></a><span class="sd">    Client names (strings) can be registered for message templates, which</span>
+</span><span id="L-689"><a href="#L-689"><span class="linenos"> 689</span></a><span class="sd">    are mappings from keys to JSON schemas:</span>
+</span><span id="L-690"><a href="#L-690"><span class="linenos"> 690</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="L-691"><a href="#L-691"><span class="linenos"> 691</span></a>
+</span><span id="L-692"><a href="#L-692"><span class="linenos"> 692</span></a><span class="sd">    The check function checks if the templates registered for a client</span>
+</span><span id="L-693"><a href="#L-693"><span class="linenos"> 693</span></a><span class="sd">    match a given message:</span>
+</span><span id="L-694"><a href="#L-694"><span class="linenos"> 694</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-695"><a href="#L-695"><span class="linenos"> 695</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-696"><a href="#L-696"><span class="linenos"> 696</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 1&#39;, m)}&quot;)</span>
+</span><span id="L-697"><a href="#L-697"><span class="linenos"> 697</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-698"><a href="#L-698"><span class="linenos"> 698</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-699"><a href="#L-699"><span class="linenos"> 699</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-700"><a href="#L-700"><span class="linenos"> 700</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-701"><a href="#L-701"><span class="linenos"> 701</span></a>
+</span><span id="L-702"><a href="#L-702"><span class="linenos"> 702</span></a><span class="sd">    Clients can be registered for values validating against arbitrary JSON</span>
+</span><span id="L-703"><a href="#L-703"><span class="linenos"> 703</span></a><span class="sd">    schemas, e.g. all values of a certain type:</span>
+</span><span id="L-704"><a href="#L-704"><span class="linenos"> 704</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="L-705"><a href="#L-705"><span class="linenos"> 705</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-706"><a href="#L-706"><span class="linenos"> 706</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-707"><a href="#L-707"><span class="linenos"> 707</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 2&#39;, m)}&quot;)</span>
+</span><span id="L-708"><a href="#L-708"><span class="linenos"> 708</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-709"><a href="#L-709"><span class="linenos"> 709</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-710"><a href="#L-710"><span class="linenos"> 710</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-711"><a href="#L-711"><span class="linenos"> 711</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-712"><a href="#L-712"><span class="linenos"> 712</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="L-713"><a href="#L-713"><span class="linenos"> 713</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-714"><a href="#L-714"><span class="linenos"> 714</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-715"><a href="#L-715"><span class="linenos"> 715</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 3&#39;, m)}&quot;)</span>
+</span><span id="L-716"><a href="#L-716"><span class="linenos"> 716</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-717"><a href="#L-717"><span class="linenos"> 717</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-718"><a href="#L-718"><span class="linenos"> 718</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-719"><a href="#L-719"><span class="linenos"> 719</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-720"><a href="#L-720"><span class="linenos"> 720</span></a>
+</span><span id="L-721"><a href="#L-721"><span class="linenos"> 721</span></a><span class="sd">    The order of key-value pairs does not have to match the order in the</span>
+</span><span id="L-722"><a href="#L-722"><span class="linenos"> 722</span></a><span class="sd">    messages and keys can be left out:</span>
+</span><span id="L-723"><a href="#L-723"><span class="linenos"> 723</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;C 4&#39;)</span>
+</span><span id="L-724"><a href="#L-724"><span class="linenos"> 724</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-725"><a href="#L-725"><span class="linenos"> 725</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-726"><a href="#L-726"><span class="linenos"> 726</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 4&#39;, m)}&quot;)</span>
+</span><span id="L-727"><a href="#L-727"><span class="linenos"> 727</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-728"><a href="#L-728"><span class="linenos"> 728</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-729"><a href="#L-729"><span class="linenos"> 729</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-730"><a href="#L-730"><span class="linenos"> 730</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-731"><a href="#L-731"><span class="linenos"> 731</span></a>
+</span><span id="L-732"><a href="#L-732"><span class="linenos"> 732</span></a><span class="sd">    A registration for an empty template matches all messages:</span>
+</span><span id="L-733"><a href="#L-733"><span class="linenos"> 733</span></a><span class="sd">    &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="L-734"><a href="#L-734"><span class="linenos"> 734</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-735"><a href="#L-735"><span class="linenos"> 735</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-736"><a href="#L-736"><span class="linenos"> 736</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 5&#39;, m)}&quot;)</span>
+</span><span id="L-737"><a href="#L-737"><span class="linenos"> 737</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-738"><a href="#L-738"><span class="linenos"> 738</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-739"><a href="#L-739"><span class="linenos"> 739</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-740"><a href="#L-740"><span class="linenos"> 740</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-741"><a href="#L-741"><span class="linenos"> 741</span></a>
+</span><span id="L-742"><a href="#L-742"><span class="linenos"> 742</span></a><span class="sd">    A client can be registered for multiple templates:</span>
+</span><span id="L-743"><a href="#L-743"><span class="linenos"> 743</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)</span>
+</span><span id="L-744"><a href="#L-744"><span class="linenos"> 744</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)</span>
+</span><span id="L-745"><a href="#L-745"><span class="linenos"> 745</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-746"><a href="#L-746"><span class="linenos"> 746</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-747"><a href="#L-747"><span class="linenos"> 747</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 6&#39;, m)}&quot;)</span>
+</span><span id="L-748"><a href="#L-748"><span class="linenos"> 748</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-749"><a href="#L-749"><span class="linenos"> 749</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-750"><a href="#L-750"><span class="linenos"> 750</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-751"><a href="#L-751"><span class="linenos"> 751</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-752"><a href="#L-752"><span class="linenos"> 752</span></a>
+</span><span id="L-753"><a href="#L-753"><span class="linenos"> 753</span></a><span class="sd">    Clients can be deregistered again (the result is False if the registry</span>
+</span><span id="L-754"><a href="#L-754"><span class="linenos"> 754</span></a><span class="sd">    is empty after the deletion):</span>
+</span><span id="L-755"><a href="#L-755"><span class="linenos"> 755</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 7&#39;)</span>
+</span><span id="L-756"><a href="#L-756"><span class="linenos"> 756</span></a><span class="sd">    &gt;&gt;&gt; r.delete(&#39;C 7&#39;)</span>
+</span><span id="L-757"><a href="#L-757"><span class="linenos"> 757</span></a><span class="sd">    True</span>
+</span><span id="L-758"><a href="#L-758"><span class="linenos"> 758</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-759"><a href="#L-759"><span class="linenos"> 759</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-760"><a href="#L-760"><span class="linenos"> 760</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 7&#39;, m)}&quot;)</span>
+</span><span id="L-761"><a href="#L-761"><span class="linenos"> 761</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-762"><a href="#L-762"><span class="linenos"> 762</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-763"><a href="#L-763"><span class="linenos"> 763</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-764"><a href="#L-764"><span class="linenos"> 764</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-765"><a href="#L-765"><span class="linenos"> 765</span></a>
+</span><span id="L-766"><a href="#L-766"><span class="linenos"> 766</span></a><span class="sd">    The get function returns all clients with registered templates matching</span>
+</span><span id="L-767"><a href="#L-767"><span class="linenos"> 767</span></a><span class="sd">    a given message:</span>
+</span><span id="L-768"><a href="#L-768"><span class="linenos"> 768</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-769"><a href="#L-769"><span class="linenos"> 769</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-770"><a href="#L-770"><span class="linenos"> 770</span></a><span class="sd">    ...     print(f&quot;{m}: {r.get(m)}&quot;)</span>
+</span><span id="L-771"><a href="#L-771"><span class="linenos"> 771</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;]</span>
+</span><span id="L-772"><a href="#L-772"><span class="linenos"> 772</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;, &#39;C 4&#39;]</span>
+</span><span id="L-773"><a href="#L-773"><span class="linenos"> 773</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 2&#39;, &#39;C 6&#39;]</span>
+</span><span id="L-774"><a href="#L-774"><span class="linenos"> 774</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 3&#39;, &#39;C 4&#39;]</span>
+</span><span id="L-775"><a href="#L-775"><span class="linenos"> 775</span></a>
+</span><span id="L-776"><a href="#L-776"><span class="linenos"> 776</span></a><span class="sd">    The get_templates function returns all templates for a given client:</span>
+</span><span id="L-777"><a href="#L-777"><span class="linenos"> 777</span></a><span class="sd">    &gt;&gt;&gt; for c in [&#39;C 1&#39;, &#39;C 2&#39;, &#39;C 3&#39;, &#39;C 4&#39;, &#39;C 5&#39;, &#39;C 6&#39;]:</span>
+</span><span id="L-778"><a href="#L-778"><span class="linenos"> 778</span></a><span class="sd">    ...     print(f&quot;{c}: {r.get_templates(c)}&quot;)</span>
+</span><span id="L-779"><a href="#L-779"><span class="linenos"> 779</span></a><span class="sd">    C 1: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="L-780"><a href="#L-780"><span class="linenos"> 780</span></a><span class="sd">    C 2: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+</span><span id="L-781"><a href="#L-781"><span class="linenos"> 781</span></a><span class="sd">    C 3: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+</span><span id="L-782"><a href="#L-782"><span class="linenos"> 782</span></a><span class="sd">    C 4: [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+</span><span id="L-783"><a href="#L-783"><span class="linenos"> 783</span></a><span class="sd">    C 5: [{}]</span>
+</span><span id="L-784"><a href="#L-784"><span class="linenos"> 784</span></a><span class="sd">    C 6: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="L-785"><a href="#L-785"><span class="linenos"> 785</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-786"><a href="#L-786"><span class="linenos"> 786</span></a>
+</span><span id="L-787"><a href="#L-787"><span class="linenos"> 787</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-788"><a href="#L-788"><span class="linenos"> 788</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise an empty registry.</span>
+</span><span id="L-789"><a href="#L-789"><span class="linenos"> 789</span></a>
+</span><span id="L-790"><a href="#L-790"><span class="linenos"> 790</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-791"><a href="#L-791"><span class="linenos"> 791</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-792"><a href="#L-792"><span class="linenos"> 792</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-793"><a href="#L-793"><span class="linenos"> 793</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-794"><a href="#L-794"><span class="linenos"> 794</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-795"><a href="#L-795"><span class="linenos"> 795</span></a>        <span class="c1"># First key is the message key, second key is the constant string</span>
+</span><span id="L-796"><a href="#L-796"><span class="linenos"> 796</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-797"><a href="#L-797"><span class="linenos"> 797</span></a>        <span class="c1"># First key is the message key, second key is the JSON schema string</span>
+</span><span id="L-798"><a href="#L-798"><span class="linenos"> 798</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-799"><a href="#L-799"><span class="linenos"> 799</span></a>
+</span><span id="L-800"><a href="#L-800"><span class="linenos"> 800</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">insert</span><span class="p">(</span>
+</span><span id="L-801"><a href="#L-801"><span class="linenos"> 801</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="L-802"><a href="#L-802"><span class="linenos"> 802</span></a>        <span class="n">template</span><span class="p">:</span> <span class="n">MessageTemplate</span><span class="p">,</span>
+</span><span id="L-803"><a href="#L-803"><span class="linenos"> 803</span></a>        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="L-804"><a href="#L-804"><span class="linenos"> 804</span></a>        <span class="n">callback</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="L-805"><a href="#L-805"><span class="linenos"> 805</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-806"><a href="#L-806"><span class="linenos"> 806</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register a client for a template.</span>
+</span><span id="L-807"><a href="#L-807"><span class="linenos"> 807</span></a>
+</span><span id="L-808"><a href="#L-808"><span class="linenos"> 808</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-809"><a href="#L-809"><span class="linenos"> 809</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="L-810"><a href="#L-810"><span class="linenos"> 810</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="L-811"><a href="#L-811"><span class="linenos"> 811</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="L-812"><a href="#L-812"><span class="linenos"> 812</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)</span>
+</span><span id="L-813"><a href="#L-813"><span class="linenos"> 813</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="L-814"><a href="#L-814"><span class="linenos"> 814</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-815"><a href="#L-815"><span class="linenos"> 815</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="L-816"><a href="#L-816"><span class="linenos"> 816</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-817"><a href="#L-817"><span class="linenos"> 817</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
+</span><span id="L-818"><a href="#L-818"><span class="linenos"> 818</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">template</span><span class="p">:</span>
+</span><span id="L-819"><a href="#L-819"><span class="linenos"> 819</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-820"><a href="#L-820"><span class="linenos"> 820</span></a>            <span class="k">if</span> <span class="n">callback</span><span class="p">:</span>
+</span><span id="L-821"><a href="#L-821"><span class="linenos"> 821</span></a>                <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="L-822"><a href="#L-822"><span class="linenos"> 822</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-823"><a href="#L-823"><span class="linenos"> 823</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="L-824"><a href="#L-824"><span class="linenos"> 824</span></a>        <span class="k">else</span><span class="p">:</span>
+</span><span id="L-825"><a href="#L-825"><span class="linenos"> 825</span></a>            <span class="n">key</span><span class="p">,</span> <span class="n">schema</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">items</span><span class="p">()))</span>
+</span><span id="L-826"><a href="#L-826"><span class="linenos"> 826</span></a>            <span class="n">reduced_template</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-827"><a href="#L-827"><span class="linenos"> 827</span></a>                <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">template</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">template</span> <span class="k">if</span> <span class="n">k</span> <span class="o">!=</span> <span class="n">key</span><span class="p">}</span>
+</span><span id="L-828"><a href="#L-828"><span class="linenos"> 828</span></a>            <span class="p">)</span>
+</span><span id="L-829"><a href="#L-829"><span class="linenos"> 829</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="L-830"><a href="#L-830"><span class="linenos"> 830</span></a>                <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span>
+</span><span id="L-831"><a href="#L-831"><span class="linenos"> 831</span></a>                <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
+</span><span id="L-832"><a href="#L-832"><span class="linenos"> 832</span></a>                <span class="ow">and</span> <span class="s2">&quot;const&quot;</span> <span class="ow">in</span> <span class="n">schema</span>
+</span><span id="L-833"><a href="#L-833"><span class="linenos"> 833</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">[</span><span class="s2">&quot;const&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-834"><a href="#L-834"><span class="linenos"> 834</span></a>            <span class="p">):</span>
+</span><span id="L-835"><a href="#L-835"><span class="linenos"> 835</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">schema</span><span class="p">[</span><span class="s2">&quot;const&quot;</span><span class="p">]</span>
+</span><span id="L-836"><a href="#L-836"><span class="linenos"> 836</span></a>                <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="L-837"><a href="#L-837"><span class="linenos"> 837</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-838"><a href="#L-838"><span class="linenos"> 838</span></a>                <span class="k">if</span> <span class="n">value</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-839"><a href="#L-839"><span class="linenos"> 839</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="L-840"><a href="#L-840"><span class="linenos"> 840</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">reduced_template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
+</span><span id="L-841"><a href="#L-841"><span class="linenos"> 841</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="L-842"><a href="#L-842"><span class="linenos"> 842</span></a>                <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="L-843"><a href="#L-843"><span class="linenos"> 843</span></a>                <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="L-844"><a href="#L-844"><span class="linenos"> 844</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-845"><a href="#L-845"><span class="linenos"> 845</span></a>                <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-846"><a href="#L-846"><span class="linenos"> 846</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="L-847"><a href="#L-847"><span class="linenos"> 847</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span>
+</span><span id="L-848"><a href="#L-848"><span class="linenos"> 848</span></a>                    <span class="n">reduced_template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span>
+</span><span id="L-849"><a href="#L-849"><span class="linenos"> 849</span></a>                <span class="p">)</span>
+</span><span id="L-850"><a href="#L-850"><span class="linenos"> 850</span></a>
+</span><span id="L-851"><a href="#L-851"><span class="linenos"> 851</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">delete</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="L-852"><a href="#L-852"><span class="linenos"> 852</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Unregister a client from all templates.</span>
+</span><span id="L-853"><a href="#L-853"><span class="linenos"> 853</span></a>
+</span><span id="L-854"><a href="#L-854"><span class="linenos"> 854</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-855"><a href="#L-855"><span class="linenos"> 855</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="L-856"><a href="#L-856"><span class="linenos"> 856</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="L-857"><a href="#L-857"><span class="linenos"> 857</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="L-858"><a href="#L-858"><span class="linenos"> 858</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)</span>
+</span><span id="L-859"><a href="#L-859"><span class="linenos"> 859</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="L-860"><a href="#L-860"><span class="linenos"> 860</span></a><span class="sd">        &gt;&gt;&gt; r.delete(&#39;C 3&#39;)</span>
+</span><span id="L-861"><a href="#L-861"><span class="linenos"> 861</span></a><span class="sd">        True</span>
+</span><span id="L-862"><a href="#L-862"><span class="linenos"> 862</span></a><span class="sd">        &gt;&gt;&gt; r.delete(&#39;C 4&#39;)</span>
+</span><span id="L-863"><a href="#L-863"><span class="linenos"> 863</span></a><span class="sd">        True</span>
+</span><span id="L-864"><a href="#L-864"><span class="linenos"> 864</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-865"><a href="#L-865"><span class="linenos"> 865</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="L-866"><a href="#L-866"><span class="linenos"> 866</span></a>            <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="L-867"><a href="#L-867"><span class="linenos"> 867</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="o">=</span> <span class="p">[</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="k">if</span> <span class="n">c</span> <span class="o">!=</span> <span class="n">client</span><span class="p">]</span>
+</span><span id="L-868"><a href="#L-868"><span class="linenos"> 868</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="L-869"><a href="#L-869"><span class="linenos"> 869</span></a>            <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="L-870"><a href="#L-870"><span class="linenos"> 870</span></a>        <span class="n">new_constants</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-871"><a href="#L-871"><span class="linenos"> 871</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="L-872"><a href="#L-872"><span class="linenos"> 872</span></a>            <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-873"><a href="#L-873"><span class="linenos"> 873</span></a>            <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-874"><a href="#L-874"><span class="linenos"> 874</span></a>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
+</span><span id="L-875"><a href="#L-875"><span class="linenos"> 875</span></a>                    <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="L-876"><a href="#L-876"><span class="linenos"> 876</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-877"><a href="#L-877"><span class="linenos"> 877</span></a>                <span class="k">del</span> <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-878"><a href="#L-878"><span class="linenos"> 878</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span> <span class="o">=</span> <span class="n">new_constants</span>
+</span><span id="L-879"><a href="#L-879"><span class="linenos"> 879</span></a>        <span class="n">new_schemas</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-880"><a href="#L-880"><span class="linenos"> 880</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="L-881"><a href="#L-881"><span class="linenos"> 881</span></a>            <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-882"><a href="#L-882"><span class="linenos"> 882</span></a>            <span class="k">for</span> <span class="n">schema</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-883"><a href="#L-883"><span class="linenos"> 883</span></a>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
+</span><span id="L-884"><a href="#L-884"><span class="linenos"> 884</span></a>                    <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span>
+</span><span id="L-885"><a href="#L-885"><span class="linenos"> 885</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-886"><a href="#L-886"><span class="linenos"> 886</span></a>                <span class="k">del</span> <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-887"><a href="#L-887"><span class="linenos"> 887</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span> <span class="o">=</span> <span class="n">new_schemas</span>
+</span><span id="L-888"><a href="#L-888"><span class="linenos"> 888</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="L-889"><a href="#L-889"><span class="linenos"> 889</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-890"><a href="#L-890"><span class="linenos"> 890</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-891"><a href="#L-891"><span class="linenos"> 891</span></a>
+</span><span id="L-892"><a href="#L-892"><span class="linenos"> 892</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="L-893"><a href="#L-893"><span class="linenos"> 893</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get if a client has a registered template matching a message.</span>
+</span><span id="L-894"><a href="#L-894"><span class="linenos"> 894</span></a>
+</span><span id="L-895"><a href="#L-895"><span class="linenos"> 895</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-896"><a href="#L-896"><span class="linenos"> 896</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="L-897"><a href="#L-897"><span class="linenos"> 897</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-898"><a href="#L-898"><span class="linenos"> 898</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-899"><a href="#L-899"><span class="linenos"> 899</span></a><span class="sd">        ...     print(f&quot;{m}: {r.check(&#39;Client 1&#39;, m)}&quot;)</span>
+</span><span id="L-900"><a href="#L-900"><span class="linenos"> 900</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="L-901"><a href="#L-901"><span class="linenos"> 901</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-902"><a href="#L-902"><span class="linenos"> 902</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-903"><a href="#L-903"><span class="linenos"> 903</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="L-904"><a href="#L-904"><span class="linenos"> 904</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="L-905"><a href="#L-905"><span class="linenos"> 905</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-906"><a href="#L-906"><span class="linenos"> 906</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-907"><a href="#L-907"><span class="linenos"> 907</span></a><span class="sd">        ...     print(f&quot;{m}: {r.check(&#39;Client 2&#39;, m)}&quot;)</span>
+</span><span id="L-908"><a href="#L-908"><span class="linenos"> 908</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-909"><a href="#L-909"><span class="linenos"> 909</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-910"><a href="#L-910"><span class="linenos"> 910</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="L-911"><a href="#L-911"><span class="linenos"> 911</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="L-912"><a href="#L-912"><span class="linenos"> 912</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-913"><a href="#L-913"><span class="linenos"> 913</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span>
+</span><span id="L-914"><a href="#L-914"><span class="linenos"> 914</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-915"><a href="#L-915"><span class="linenos"> 915</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="L-916"><a href="#L-916"><span class="linenos"> 916</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="L-917"><a href="#L-917"><span class="linenos"> 917</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="L-918"><a href="#L-918"><span class="linenos"> 918</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-919"><a href="#L-919"><span class="linenos"> 919</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-920"><a href="#L-920"><span class="linenos"> 920</span></a>            <span class="p">):</span>
+</span><span id="L-921"><a href="#L-921"><span class="linenos"> 921</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-922"><a href="#L-922"><span class="linenos"> 922</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-923"><a href="#L-923"><span class="linenos"> 923</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="L-924"><a href="#L-924"><span class="linenos"> 924</span></a>                <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="L-925"><a href="#L-925"><span class="linenos"> 925</span></a>                    <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-926"><a href="#L-926"><span class="linenos"> 926</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="L-927"><a href="#L-927"><span class="linenos"> 927</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-928"><a href="#L-928"><span class="linenos"> 928</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-929"><a href="#L-929"><span class="linenos"> 929</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="L-930"><a href="#L-930"><span class="linenos"> 930</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="L-931"><a href="#L-931"><span class="linenos"> 931</span></a>                        <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="L-932"><a href="#L-932"><span class="linenos"> 932</span></a>                            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="L-933"><a href="#L-933"><span class="linenos"> 933</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="L-934"><a href="#L-934"><span class="linenos"> 934</span></a>
+</span><span id="L-935"><a href="#L-935"><span class="linenos"> 935</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
+</span><span id="L-936"><a href="#L-936"><span class="linenos"> 936</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all clients registered for templates matching a message.</span>
+</span><span id="L-937"><a href="#L-937"><span class="linenos"> 937</span></a>
+</span><span id="L-938"><a href="#L-938"><span class="linenos"> 938</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-939"><a href="#L-939"><span class="linenos"> 939</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="L-940"><a href="#L-940"><span class="linenos"> 940</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="L-941"><a href="#L-941"><span class="linenos"> 941</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="L-942"><a href="#L-942"><span class="linenos"> 942</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="L-943"><a href="#L-943"><span class="linenos"> 943</span></a><span class="sd">        ...     print(f&quot;{m}: {r.get(m)}&quot;)</span>
+</span><span id="L-944"><a href="#L-944"><span class="linenos"> 944</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]</span>
+</span><span id="L-945"><a href="#L-945"><span class="linenos"> 945</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;Client 1&#39;, &#39;Client 2&#39;]</span>
+</span><span id="L-946"><a href="#L-946"><span class="linenos"> 946</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []</span>
+</span><span id="L-947"><a href="#L-947"><span class="linenos"> 947</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;Client 2&#39;]</span>
+</span><span id="L-948"><a href="#L-948"><span class="linenos"> 948</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-949"><a href="#L-949"><span class="linenos"> 949</span></a>        <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-950"><a href="#L-950"><span class="linenos"> 950</span></a>        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span>
+</span><span id="L-951"><a href="#L-951"><span class="linenos"> 951</span></a>            <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="L-952"><a href="#L-952"><span class="linenos"> 952</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-953"><a href="#L-953"><span class="linenos"> 953</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="L-954"><a href="#L-954"><span class="linenos"> 954</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="L-955"><a href="#L-955"><span class="linenos"> 955</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="L-956"><a href="#L-956"><span class="linenos"> 956</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-957"><a href="#L-957"><span class="linenos"> 957</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-958"><a href="#L-958"><span class="linenos"> 958</span></a>            <span class="p">):</span>
+</span><span id="L-959"><a href="#L-959"><span class="linenos"> 959</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-960"><a href="#L-960"><span class="linenos"> 960</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-961"><a href="#L-961"><span class="linenos"> 961</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="L-962"><a href="#L-962"><span class="linenos"> 962</span></a>                <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="L-963"><a href="#L-963"><span class="linenos"> 963</span></a>                    <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="L-964"><a href="#L-964"><span class="linenos"> 964</span></a>                        <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-965"><a href="#L-965"><span class="linenos"> 965</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="L-966"><a href="#L-966"><span class="linenos"> 966</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-967"><a href="#L-967"><span class="linenos"> 967</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-968"><a href="#L-968"><span class="linenos"> 968</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="L-969"><a href="#L-969"><span class="linenos"> 969</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="L-970"><a href="#L-970"><span class="linenos"> 970</span></a>                        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="L-971"><a href="#L-971"><span class="linenos"> 971</span></a>                            <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="L-972"><a href="#L-972"><span class="linenos"> 972</span></a>                                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-973"><a href="#L-973"><span class="linenos"> 973</span></a>        <span class="k">return</span> <span class="n">result</span>
+</span><span id="L-974"><a href="#L-974"><span class="linenos"> 974</span></a>
+</span><span id="L-975"><a href="#L-975"><span class="linenos"> 975</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get_callbacks</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]:</span>
+</span><span id="L-976"><a href="#L-976"><span class="linenos"> 976</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all callbacks registered for templates matching a message.&quot;&quot;&quot;</span>
+</span><span id="L-977"><a href="#L-977"><span class="linenos"> 977</span></a>        <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-978"><a href="#L-978"><span class="linenos"> 978</span></a>        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="L-979"><a href="#L-979"><span class="linenos"> 979</span></a>            <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]:</span>
+</span><span id="L-980"><a href="#L-980"><span class="linenos"> 980</span></a>                <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="L-981"><a href="#L-981"><span class="linenos"> 981</span></a>                    <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="L-982"><a href="#L-982"><span class="linenos"> 982</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="L-983"><a href="#L-983"><span class="linenos"> 983</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="L-984"><a href="#L-984"><span class="linenos"> 984</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="L-985"><a href="#L-985"><span class="linenos"> 985</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-986"><a href="#L-986"><span class="linenos"> 986</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-987"><a href="#L-987"><span class="linenos"> 987</span></a>            <span class="p">):</span>
+</span><span id="L-988"><a href="#L-988"><span class="linenos"> 988</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-989"><a href="#L-989"><span class="linenos"> 989</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-990"><a href="#L-990"><span class="linenos"> 990</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="L-991"><a href="#L-991"><span class="linenos"> 991</span></a>                <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="L-992"><a href="#L-992"><span class="linenos"> 992</span></a>                    <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="L-993"><a href="#L-993"><span class="linenos"> 993</span></a>                        <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="L-994"><a href="#L-994"><span class="linenos"> 994</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="L-995"><a href="#L-995"><span class="linenos"> 995</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-996"><a href="#L-996"><span class="linenos"> 996</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="L-997"><a href="#L-997"><span class="linenos"> 997</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="L-998"><a href="#L-998"><span class="linenos"> 998</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="L-999"><a href="#L-999"><span class="linenos"> 999</span></a>                        <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="L-1000"><a href="#L-1000"><span class="linenos">1000</span></a>                            <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="L-1001"><a href="#L-1001"><span class="linenos">1001</span></a>                                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="L-1002"><a href="#L-1002"><span class="linenos">1002</span></a>        <span class="k">return</span> <span class="n">result</span>
+</span><span id="L-1003"><a href="#L-1003"><span class="linenos">1003</span></a>
+</span><span id="L-1004"><a href="#L-1004"><span class="linenos">1004</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get_templates</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]:</span>
+</span><span id="L-1005"><a href="#L-1005"><span class="linenos">1005</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all templates for a client.</span>
+</span><span id="L-1006"><a href="#L-1006"><span class="linenos">1006</span></a>
+</span><span id="L-1007"><a href="#L-1007"><span class="linenos">1007</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="L-1008"><a href="#L-1008"><span class="linenos">1008</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="L-1009"><a href="#L-1009"><span class="linenos">1009</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 1&#39;)</span>
+</span><span id="L-1010"><a href="#L-1010"><span class="linenos">1010</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="L-1011"><a href="#L-1011"><span class="linenos">1011</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},</span>
+</span><span id="L-1012"><a href="#L-1012"><span class="linenos">1012</span></a><span class="sd">        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="L-1013"><a href="#L-1013"><span class="linenos">1013</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 2&#39;)</span>
+</span><span id="L-1014"><a href="#L-1014"><span class="linenos">1014</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+</span><span id="L-1015"><a href="#L-1015"><span class="linenos">1015</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},</span>
+</span><span id="L-1016"><a href="#L-1016"><span class="linenos">1016</span></a><span class="sd">        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 3&#39;)</span>
+</span><span id="L-1017"><a href="#L-1017"><span class="linenos">1017</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 3&#39;)</span>
+</span><span id="L-1018"><a href="#L-1018"><span class="linenos">1018</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+</span><span id="L-1019"><a href="#L-1019"><span class="linenos">1019</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;Client 4&#39;)</span>
+</span><span id="L-1020"><a href="#L-1020"><span class="linenos">1020</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 4&#39;)</span>
+</span><span id="L-1021"><a href="#L-1021"><span class="linenos">1021</span></a><span class="sd">        [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+</span><span id="L-1022"><a href="#L-1022"><span class="linenos">1022</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;Client 5&#39;)</span>
+</span><span id="L-1023"><a href="#L-1023"><span class="linenos">1023</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 5&#39;)</span>
+</span><span id="L-1024"><a href="#L-1024"><span class="linenos">1024</span></a><span class="sd">        [{}]</span>
+</span><span id="L-1025"><a href="#L-1025"><span class="linenos">1025</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)</span>
+</span><span id="L-1026"><a href="#L-1026"><span class="linenos">1026</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)</span>
+</span><span id="L-1027"><a href="#L-1027"><span class="linenos">1027</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 6&#39;)</span>
+</span><span id="L-1028"><a href="#L-1028"><span class="linenos">1028</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="L-1029"><a href="#L-1029"><span class="linenos">1029</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1030"><a href="#L-1030"><span class="linenos">1030</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="L-1031"><a href="#L-1031"><span class="linenos">1031</span></a>            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="L-1032"><a href="#L-1032"><span class="linenos">1032</span></a>        <span class="k">return</span> <span class="p">[]</span>
+</span><span id="L-1033"><a href="#L-1033"><span class="linenos">1033</span></a>
+</span><span id="L-1034"><a href="#L-1034"><span class="linenos">1034</span></a>
+</span><span id="L-1035"><a href="#L-1035"><span class="linenos">1035</span></a><span class="k">class</span><span class="w"> </span><span class="nc">BusException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+</span><span id="L-1036"><a href="#L-1036"><span class="linenos">1036</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Raise for errors in using message bus.&quot;&quot;&quot;</span>
+</span><span id="L-1037"><a href="#L-1037"><span class="linenos">1037</span></a>
+</span><span id="L-1038"><a href="#L-1038"><span class="linenos">1038</span></a>
+</span><span id="L-1039"><a href="#L-1039"><span class="linenos">1039</span></a><span class="k">class</span><span class="w"> </span><span class="nc">MessageBus</span><span class="p">:</span>
+</span><span id="L-1040"><a href="#L-1040"><span class="linenos">1040</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Provide an asynchronous message bus.</span>
+</span><span id="L-1041"><a href="#L-1041"><span class="linenos">1041</span></a>
+</span><span id="L-1042"><a href="#L-1042"><span class="linenos">1042</span></a><span class="sd">    The bus executes asynchronous callbacks for all messages to be received</span>
+</span><span id="L-1043"><a href="#L-1043"><span class="linenos">1043</span></a><span class="sd">    by a client. We use a simple callback printing the message in all</span>
+</span><span id="L-1044"><a href="#L-1044"><span class="linenos">1044</span></a><span class="sd">    examples:</span>
+</span><span id="L-1045"><a href="#L-1045"><span class="linenos">1045</span></a><span class="sd">    &gt;&gt;&gt; def callback_for_receiver(receiver):</span>
+</span><span id="L-1046"><a href="#L-1046"><span class="linenos">1046</span></a><span class="sd">    ...     print(f&quot;Creating callback for {receiver}.&quot;)</span>
+</span><span id="L-1047"><a href="#L-1047"><span class="linenos">1047</span></a><span class="sd">    ...     async def callback(message):</span>
+</span><span id="L-1048"><a href="#L-1048"><span class="linenos">1048</span></a><span class="sd">    ...         print(f&quot;{receiver}: {message}&quot;)</span>
+</span><span id="L-1049"><a href="#L-1049"><span class="linenos">1049</span></a><span class="sd">    ...     return callback</span>
+</span><span id="L-1050"><a href="#L-1050"><span class="linenos">1050</span></a>
+</span><span id="L-1051"><a href="#L-1051"><span class="linenos">1051</span></a><span class="sd">    Clients can be registered at the bus with a name, lists of message</span>
+</span><span id="L-1052"><a href="#L-1052"><span class="linenos">1052</span></a><span class="sd">    templates they want to use for sending and receiving and a callback</span>
+</span><span id="L-1053"><a href="#L-1053"><span class="linenos">1053</span></a><span class="sd">    function for receiving. An empty list of templates means that the</span>
+</span><span id="L-1054"><a href="#L-1054"><span class="linenos">1054</span></a><span class="sd">    client does not want to send or receive any messages, respectively.</span>
+</span><span id="L-1055"><a href="#L-1055"><span class="linenos">1055</span></a><span class="sd">    A list with an empty template means that it wants to send arbitrary</span>
+</span><span id="L-1056"><a href="#L-1056"><span class="linenos">1056</span></a><span class="sd">    or receive all messages, respectively:</span>
+</span><span id="L-1057"><a href="#L-1057"><span class="linenos">1057</span></a><span class="sd">    &gt;&gt;&gt; async def setup(bus):</span>
+</span><span id="L-1058"><a href="#L-1058"><span class="linenos">1058</span></a><span class="sd">    ...     print(&quot;Setting up.&quot;)</span>
+</span><span id="L-1059"><a href="#L-1059"><span class="linenos">1059</span></a><span class="sd">    ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1060"><a href="#L-1060"><span class="linenos">1060</span></a><span class="sd">    ...                  [],</span>
+</span><span id="L-1061"><a href="#L-1061"><span class="linenos">1061</span></a><span class="sd">    ...                  [([MessageTemplate({})],</span>
+</span><span id="L-1062"><a href="#L-1062"><span class="linenos">1062</span></a><span class="sd">    ...                    callback_for_receiver(&#39;Logger&#39;))])</span>
+</span><span id="L-1063"><a href="#L-1063"><span class="linenos">1063</span></a><span class="sd">    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1064"><a href="#L-1064"><span class="linenos">1064</span></a><span class="sd">    ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="L-1065"><a href="#L-1065"><span class="linenos">1065</span></a><span class="sd">    ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1066"><a href="#L-1066"><span class="linenos">1066</span></a><span class="sd">    ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="L-1067"><a href="#L-1067"><span class="linenos">1067</span></a><span class="sd">    ...                    callback_for_receiver(&#39;Client 1&#39;))])</span>
+</span><span id="L-1068"><a href="#L-1068"><span class="linenos">1068</span></a><span class="sd">    ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1069"><a href="#L-1069"><span class="linenos">1069</span></a><span class="sd">    ...                  [MessageTemplate({})],</span>
+</span><span id="L-1070"><a href="#L-1070"><span class="linenos">1070</span></a><span class="sd">    ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1071"><a href="#L-1071"><span class="linenos">1071</span></a><span class="sd">    ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="L-1072"><a href="#L-1072"><span class="linenos">1072</span></a><span class="sd">    ...                    callback_for_receiver(&#39;Client 2&#39;))])</span>
+</span><span id="L-1073"><a href="#L-1073"><span class="linenos">1073</span></a>
+</span><span id="L-1074"><a href="#L-1074"><span class="linenos">1074</span></a><span class="sd">    The bus itself is addressed by the empty string. It sends messages for</span>
+</span><span id="L-1075"><a href="#L-1075"><span class="linenos">1075</span></a><span class="sd">    each registration and deregestration of a client with a key &#39;event&#39; and</span>
+</span><span id="L-1076"><a href="#L-1076"><span class="linenos">1076</span></a><span class="sd">    a value of &#39;registered&#39; or &#39;unregistered&#39;, a key &#39;client&#39; with the</span>
+</span><span id="L-1077"><a href="#L-1077"><span class="linenos">1077</span></a><span class="sd">    client&#39;s name as value and for registrations also keys &#39;sends&#39; and</span>
+</span><span id="L-1078"><a href="#L-1078"><span class="linenos">1078</span></a><span class="sd">    &#39;receives&#39; with all templates registered for the client for sending and</span>
+</span><span id="L-1079"><a href="#L-1079"><span class="linenos">1079</span></a><span class="sd">    receiving.</span>
+</span><span id="L-1080"><a href="#L-1080"><span class="linenos">1080</span></a>
+</span><span id="L-1081"><a href="#L-1081"><span class="linenos">1081</span></a><span class="sd">    Clients can send to the bus with the send function. Each message has to</span>
+</span><span id="L-1082"><a href="#L-1082"><span class="linenos">1082</span></a><span class="sd">    declare a sender. The send templates of that sender are checked for a</span>
+</span><span id="L-1083"><a href="#L-1083"><span class="linenos">1083</span></a><span class="sd">    template matching the message. We cannot prevent arbitrary code from</span>
+</span><span id="L-1084"><a href="#L-1084"><span class="linenos">1084</span></a><span class="sd">    impersonating any sender, but this should only be done in debugging or</span>
+</span><span id="L-1085"><a href="#L-1085"><span class="linenos">1085</span></a><span class="sd">    management situations.</span>
+</span><span id="L-1086"><a href="#L-1086"><span class="linenos">1086</span></a>
+</span><span id="L-1087"><a href="#L-1087"><span class="linenos">1087</span></a><span class="sd">    Messages that are intended for a specific client by convention have a</span>
+</span><span id="L-1088"><a href="#L-1088"><span class="linenos">1088</span></a><span class="sd">    key &#39;target&#39; with the target client&#39;s name as value. Such messages are</span>
+</span><span id="L-1089"><a href="#L-1089"><span class="linenos">1089</span></a><span class="sd">    often commands to the client to do something, which is by convention</span>
+</span><span id="L-1090"><a href="#L-1090"><span class="linenos">1090</span></a><span class="sd">    indicated by a key &#39;command&#39; with a value that indicates what should be</span>
+</span><span id="L-1091"><a href="#L-1091"><span class="linenos">1091</span></a><span class="sd">    done.</span>
+</span><span id="L-1092"><a href="#L-1092"><span class="linenos">1092</span></a>
+</span><span id="L-1093"><a href="#L-1093"><span class="linenos">1093</span></a><span class="sd">    The bus, for example, reacts to a message with &#39;target&#39;: &#39;&#39; and</span>
+</span><span id="L-1094"><a href="#L-1094"><span class="linenos">1094</span></a><span class="sd">    &#39;command&#39;: &#39;get clients&#39; by sending one message for each currently</span>
+</span><span id="L-1095"><a href="#L-1095"><span class="linenos">1095</span></a><span class="sd">    registered with complete information about its registered send and</span>
+</span><span id="L-1096"><a href="#L-1096"><span class="linenos">1096</span></a><span class="sd">    receive templates.</span>
+</span><span id="L-1097"><a href="#L-1097"><span class="linenos">1097</span></a>
+</span><span id="L-1098"><a href="#L-1098"><span class="linenos">1098</span></a><span class="sd">    &gt;&gt;&gt; async def send(bus):</span>
+</span><span id="L-1099"><a href="#L-1099"><span class="linenos">1099</span></a><span class="sd">    ...     print(&quot;Sending messages.&quot;)</span>
+</span><span id="L-1100"><a href="#L-1100"><span class="linenos">1100</span></a><span class="sd">    ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="L-1101"><a href="#L-1101"><span class="linenos">1101</span></a><span class="sd">    ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="L-1102"><a href="#L-1102"><span class="linenos">1102</span></a><span class="sd">    ...     await bus.send({&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;,</span>
+</span><span id="L-1103"><a href="#L-1103"><span class="linenos">1103</span></a><span class="sd">    ...                     &#39;command&#39;: &#39;get clients&#39;})</span>
+</span><span id="L-1104"><a href="#L-1104"><span class="linenos">1104</span></a>
+</span><span id="L-1105"><a href="#L-1105"><span class="linenos">1105</span></a><span class="sd">    The run function executes the message bus forever. If we want to stop</span>
+</span><span id="L-1106"><a href="#L-1106"><span class="linenos">1106</span></a><span class="sd">    it, we have to explicitly cancel the task:</span>
+</span><span id="L-1107"><a href="#L-1107"><span class="linenos">1107</span></a><span class="sd">    &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1108"><a href="#L-1108"><span class="linenos">1108</span></a><span class="sd">    ...     bus = MessageBus()</span>
+</span><span id="L-1109"><a href="#L-1109"><span class="linenos">1109</span></a><span class="sd">    ...     await setup(bus)</span>
+</span><span id="L-1110"><a href="#L-1110"><span class="linenos">1110</span></a><span class="sd">    ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="L-1111"><a href="#L-1111"><span class="linenos">1111</span></a><span class="sd">    ...     await send(bus)</span>
+</span><span id="L-1112"><a href="#L-1112"><span class="linenos">1112</span></a><span class="sd">    ...     await asyncio.sleep(0)</span>
+</span><span id="L-1113"><a href="#L-1113"><span class="linenos">1113</span></a><span class="sd">    ...     bus_task.cancel()</span>
+</span><span id="L-1114"><a href="#L-1114"><span class="linenos">1114</span></a><span class="sd">    ...     try:</span>
+</span><span id="L-1115"><a href="#L-1115"><span class="linenos">1115</span></a><span class="sd">    ...         await bus_task</span>
+</span><span id="L-1116"><a href="#L-1116"><span class="linenos">1116</span></a><span class="sd">    ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-1117"><a href="#L-1117"><span class="linenos">1117</span></a><span class="sd">    ...         pass</span>
+</span><span id="L-1118"><a href="#L-1118"><span class="linenos">1118</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-1119"><a href="#L-1119"><span class="linenos">1119</span></a><span class="sd">    Setting up.</span>
+</span><span id="L-1120"><a href="#L-1120"><span class="linenos">1120</span></a><span class="sd">    Creating callback for Logger.</span>
+</span><span id="L-1121"><a href="#L-1121"><span class="linenos">1121</span></a><span class="sd">    Creating callback for Client 1.</span>
+</span><span id="L-1122"><a href="#L-1122"><span class="linenos">1122</span></a><span class="sd">    Creating callback for Client 2.</span>
+</span><span id="L-1123"><a href="#L-1123"><span class="linenos">1123</span></a><span class="sd">    Sending messages.</span>
+</span><span id="L-1124"><a href="#L-1124"><span class="linenos">1124</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-1125"><a href="#L-1125"><span class="linenos">1125</span></a><span class="sd">             &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-1126"><a href="#L-1126"><span class="linenos">1126</span></a><span class="sd">             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+</span><span id="L-1127"><a href="#L-1127"><span class="linenos">1127</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-1128"><a href="#L-1128"><span class="linenos">1128</span></a><span class="sd">             &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-1129"><a href="#L-1129"><span class="linenos">1129</span></a><span class="sd">             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-1130"><a href="#L-1130"><span class="linenos">1130</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+</span><span id="L-1131"><a href="#L-1131"><span class="linenos">1131</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-1132"><a href="#L-1132"><span class="linenos">1132</span></a><span class="sd">             &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-1133"><a href="#L-1133"><span class="linenos">1133</span></a><span class="sd">             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>
+</span><span id="L-1134"><a href="#L-1134"><span class="linenos">1134</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="L-1135"><a href="#L-1135"><span class="linenos">1135</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="L-1136"><a href="#L-1136"><span class="linenos">1136</span></a><span class="sd">    Client 1: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="L-1137"><a href="#L-1137"><span class="linenos">1137</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;, &#39;command&#39;: &#39;get clients&#39;}</span>
+</span><span id="L-1138"><a href="#L-1138"><span class="linenos">1138</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-1139"><a href="#L-1139"><span class="linenos">1139</span></a><span class="sd">             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+</span><span id="L-1140"><a href="#L-1140"><span class="linenos">1140</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-1141"><a href="#L-1141"><span class="linenos">1141</span></a><span class="sd">             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-1142"><a href="#L-1142"><span class="linenos">1142</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+</span><span id="L-1143"><a href="#L-1143"><span class="linenos">1143</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="L-1144"><a href="#L-1144"><span class="linenos">1144</span></a><span class="sd">             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>
+</span><span id="L-1145"><a href="#L-1145"><span class="linenos">1145</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-1146"><a href="#L-1146"><span class="linenos">1146</span></a>
+</span><span id="L-1147"><a href="#L-1147"><span class="linenos">1147</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-1148"><a href="#L-1148"><span class="linenos">1148</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise a new bus without clients.</span>
+</span><span id="L-1149"><a href="#L-1149"><span class="linenos">1149</span></a>
+</span><span id="L-1150"><a href="#L-1150"><span class="linenos">1150</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1151"><a href="#L-1151"><span class="linenos">1151</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="L-1152"><a href="#L-1152"><span class="linenos">1152</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="L-1153"><a href="#L-1153"><span class="linenos">1153</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1154"><a href="#L-1154"><span class="linenos">1154</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Queue</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Queue</span><span class="p">()</span>
+</span><span id="L-1155"><a href="#L-1155"><span class="linenos">1155</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-1156"><a href="#L-1156"><span class="linenos">1156</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="p">:</span> <span class="n">TemplateRegistry</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="L-1157"><a href="#L-1157"><span class="linenos">1157</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="p">:</span> <span class="n">TemplateRegistry</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="L-1158"><a href="#L-1158"><span class="linenos">1158</span></a>
+</span><span id="L-1159"><a href="#L-1159"><span class="linenos">1159</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">register</span><span class="p">(</span>
+</span><span id="L-1160"><a href="#L-1160"><span class="linenos">1160</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="L-1161"><a href="#L-1161"><span class="linenos">1161</span></a>        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="L-1162"><a href="#L-1162"><span class="linenos">1162</span></a>        <span class="n">plugin</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="L-1163"><a href="#L-1163"><span class="linenos">1163</span></a>        <span class="n">sends</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">],</span>
+</span><span id="L-1164"><a href="#L-1164"><span class="linenos">1164</span></a>        <span class="n">receives</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">],</span> <span class="n">MessageCallback</span><span class="p">]],</span>
+</span><span id="L-1165"><a href="#L-1165"><span class="linenos">1165</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-1166"><a href="#L-1166"><span class="linenos">1166</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register a client at the message bus.</span>
+</span><span id="L-1167"><a href="#L-1167"><span class="linenos">1167</span></a>
+</span><span id="L-1168"><a href="#L-1168"><span class="linenos">1168</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="L-1169"><a href="#L-1169"><span class="linenos">1169</span></a><span class="sd">        ...     print(message)</span>
+</span><span id="L-1170"><a href="#L-1170"><span class="linenos">1170</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1171"><a href="#L-1171"><span class="linenos">1171</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="L-1172"><a href="#L-1172"><span class="linenos">1172</span></a><span class="sd">        ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1173"><a href="#L-1173"><span class="linenos">1173</span></a><span class="sd">        ...                  [],    # send nothing</span>
+</span><span id="L-1174"><a href="#L-1174"><span class="linenos">1174</span></a><span class="sd">        ...                  [([MessageTemplate({})],  # receive everything</span>
+</span><span id="L-1175"><a href="#L-1175"><span class="linenos">1175</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1176"><a href="#L-1176"><span class="linenos">1176</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1177"><a href="#L-1177"><span class="linenos">1177</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="L-1178"><a href="#L-1178"><span class="linenos">1178</span></a><span class="sd">        ...                      # send with key &#39;k1&#39; and string value</span>
+</span><span id="L-1179"><a href="#L-1179"><span class="linenos">1179</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1180"><a href="#L-1180"><span class="linenos">1180</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="L-1181"><a href="#L-1181"><span class="linenos">1181</span></a><span class="sd">        ...                      # receive for this client</span>
+</span><span id="L-1182"><a href="#L-1182"><span class="linenos">1182</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1183"><a href="#L-1183"><span class="linenos">1183</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1184"><a href="#L-1184"><span class="linenos">1184</span></a><span class="sd">        ...                  [MessageTemplate({})],  # send arbitrary</span>
+</span><span id="L-1185"><a href="#L-1185"><span class="linenos">1185</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1186"><a href="#L-1186"><span class="linenos">1186</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="L-1187"><a href="#L-1187"><span class="linenos">1187</span></a><span class="sd">        ...                      # receive for this client</span>
+</span><span id="L-1188"><a href="#L-1188"><span class="linenos">1188</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1189"><a href="#L-1189"><span class="linenos">1189</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="L-1190"><a href="#L-1190"><span class="linenos">1190</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1191"><a href="#L-1191"><span class="linenos">1191</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">client</span><span class="p">:</span>
+</span><span id="L-1192"><a href="#L-1192"><span class="linenos">1192</span></a>            <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span><span class="s2">&quot;Client name is not allowed to be empty.&quot;</span><span class="p">)</span>
+</span><span id="L-1193"><a href="#L-1193"><span class="linenos">1193</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="L-1194"><a href="#L-1194"><span class="linenos">1194</span></a>            <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Client &#39;</span><span class="si">{</span><span class="n">client</span><span class="si">}</span><span class="s2">&#39; already registered at message bus.&quot;</span><span class="p">)</span>
+</span><span id="L-1195"><a href="#L-1195"><span class="linenos">1195</span></a>        <span class="n">event</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="L-1196"><a href="#L-1196"><span class="linenos">1196</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;registered&quot;</span>
+</span><span id="L-1197"><a href="#L-1197"><span class="linenos">1197</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="L-1198"><a href="#L-1198"><span class="linenos">1198</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="n">plugin</span>
+</span><span id="L-1199"><a href="#L-1199"><span class="linenos">1199</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">plugin</span>
+</span><span id="L-1200"><a href="#L-1200"><span class="linenos">1200</span></a>        <span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">sends</span><span class="p">:</span>
+</span><span id="L-1201"><a href="#L-1201"><span class="linenos">1201</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span>
+</span><span id="L-1202"><a href="#L-1202"><span class="linenos">1202</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;sends&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-1203"><a href="#L-1203"><span class="linenos">1203</span></a>        <span class="k">for</span> <span class="n">templates</span><span class="p">,</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">receives</span><span class="p">:</span>
+</span><span id="L-1204"><a href="#L-1204"><span class="linenos">1204</span></a>            <span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">templates</span><span class="p">:</span>
+</span><span id="L-1205"><a href="#L-1205"><span class="linenos">1205</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
+</span><span id="L-1206"><a href="#L-1206"><span class="linenos">1206</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;receives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-1207"><a href="#L-1207"><span class="linenos">1207</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
+</span><span id="L-1208"><a href="#L-1208"><span class="linenos">1208</span></a>
+</span><span id="L-1209"><a href="#L-1209"><span class="linenos">1209</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">unregister</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-1210"><a href="#L-1210"><span class="linenos">1210</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Unregister a client from the message bus.</span>
+</span><span id="L-1211"><a href="#L-1211"><span class="linenos">1211</span></a>
+</span><span id="L-1212"><a href="#L-1212"><span class="linenos">1212</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="L-1213"><a href="#L-1213"><span class="linenos">1213</span></a><span class="sd">        ...     print(message)</span>
+</span><span id="L-1214"><a href="#L-1214"><span class="linenos">1214</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1215"><a href="#L-1215"><span class="linenos">1215</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="L-1216"><a href="#L-1216"><span class="linenos">1216</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1217"><a href="#L-1217"><span class="linenos">1217</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="L-1218"><a href="#L-1218"><span class="linenos">1218</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1219"><a href="#L-1219"><span class="linenos">1219</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="L-1220"><a href="#L-1220"><span class="linenos">1220</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1221"><a href="#L-1221"><span class="linenos">1221</span></a><span class="sd">        ...     bus.unregister(&#39;Client 1&#39;)</span>
+</span><span id="L-1222"><a href="#L-1222"><span class="linenos">1222</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="L-1223"><a href="#L-1223"><span class="linenos">1223</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1224"><a href="#L-1224"><span class="linenos">1224</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="L-1225"><a href="#L-1225"><span class="linenos">1225</span></a>            <span class="k">return</span>
+</span><span id="L-1226"><a href="#L-1226"><span class="linenos">1226</span></a>        <span class="n">event</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="L-1227"><a href="#L-1227"><span class="linenos">1227</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;unregistered&quot;</span>
+</span><span id="L-1228"><a href="#L-1228"><span class="linenos">1228</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="L-1229"><a href="#L-1229"><span class="linenos">1229</span></a>        <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="L-1230"><a href="#L-1230"><span class="linenos">1230</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-1231"><a href="#L-1231"><span class="linenos">1231</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-1232"><a href="#L-1232"><span class="linenos">1232</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
+</span><span id="L-1233"><a href="#L-1233"><span class="linenos">1233</span></a>
+</span><span id="L-1234"><a href="#L-1234"><span class="linenos">1234</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-1235"><a href="#L-1235"><span class="linenos">1235</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the message bus forever.</span>
+</span><span id="L-1236"><a href="#L-1236"><span class="linenos">1236</span></a>
+</span><span id="L-1237"><a href="#L-1237"><span class="linenos">1237</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1238"><a href="#L-1238"><span class="linenos">1238</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="L-1239"><a href="#L-1239"><span class="linenos">1239</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="L-1240"><a href="#L-1240"><span class="linenos">1240</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="L-1241"><a href="#L-1241"><span class="linenos">1241</span></a><span class="sd">        ...     try:</span>
+</span><span id="L-1242"><a href="#L-1242"><span class="linenos">1242</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="L-1243"><a href="#L-1243"><span class="linenos">1243</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-1244"><a href="#L-1244"><span class="linenos">1244</span></a><span class="sd">        ...         pass</span>
+</span><span id="L-1245"><a href="#L-1245"><span class="linenos">1245</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="L-1246"><a href="#L-1246"><span class="linenos">1246</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1247"><a href="#L-1247"><span class="linenos">1247</span></a>        <span class="n">background_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="L-1248"><a href="#L-1248"><span class="linenos">1248</span></a>        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
+</span><span id="L-1249"><a href="#L-1249"><span class="linenos">1249</span></a>            <span class="n">message</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
+</span><span id="L-1250"><a href="#L-1250"><span class="linenos">1250</span></a>            <span class="k">if</span> <span class="s2">&quot;target&quot;</span> <span class="ow">in</span> <span class="n">message</span> <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;target&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="s2">&quot;command&quot;</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-1251"><a href="#L-1251"><span class="linenos">1251</span></a>                <span class="k">if</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;get clients&quot;</span><span class="p">:</span>
+</span><span id="L-1252"><a href="#L-1252"><span class="linenos">1252</span></a>                    <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="L-1253"><a href="#L-1253"><span class="linenos">1253</span></a>                        <span class="n">answer</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="L-1254"><a href="#L-1254"><span class="linenos">1254</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="L-1255"><a href="#L-1255"><span class="linenos">1255</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="L-1256"><a href="#L-1256"><span class="linenos">1256</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;sends&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-1257"><a href="#L-1257"><span class="linenos">1257</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;receives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="L-1258"><a href="#L-1258"><span class="linenos">1258</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
+</span><span id="L-1259"><a href="#L-1259"><span class="linenos">1259</span></a>                <span class="k">elif</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;push conf&quot;</span><span class="p">:</span>
+</span><span id="L-1260"><a href="#L-1260"><span class="linenos">1260</span></a>                    <span class="n">conf</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-1261"><a href="#L-1261"><span class="linenos">1261</span></a>                    <span class="k">try</span><span class="p">:</span>
+</span><span id="L-1262"><a href="#L-1262"><span class="linenos">1262</span></a>                        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">as</span> <span class="n">conf_file</span><span class="p">:</span>
+</span><span id="L-1263"><a href="#L-1263"><span class="linenos">1263</span></a>                            <span class="n">conf</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">conf_file</span><span class="p">)</span>
+</span><span id="L-1264"><a href="#L-1264"><span class="linenos">1264</span></a>                    <span class="k">except</span> <span class="p">(</span>
+</span><span id="L-1265"><a href="#L-1265"><span class="linenos">1265</span></a>                        <span class="ne">IndexError</span><span class="p">,</span>
+</span><span id="L-1266"><a href="#L-1266"><span class="linenos">1266</span></a>                        <span class="ne">FileNotFoundError</span><span class="p">,</span>
+</span><span id="L-1267"><a href="#L-1267"><span class="linenos">1267</span></a>                        <span class="n">json</span><span class="o">.</span><span class="n">decoder</span><span class="o">.</span><span class="n">JSONDecodeError</span><span class="p">,</span>
+</span><span id="L-1268"><a href="#L-1268"><span class="linenos">1268</span></a>                    <span class="p">):</span>
+</span><span id="L-1269"><a href="#L-1269"><span class="linenos">1269</span></a>                        <span class="k">pass</span>
+</span><span id="L-1270"><a href="#L-1270"><span class="linenos">1270</span></a>                    <span class="k">if</span> <span class="n">conf</span> <span class="o">==</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;conf&quot;</span><span class="p">]:</span>
+</span><span id="L-1271"><a href="#L-1271"><span class="linenos">1271</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;conf unchanged&quot;</span><span class="p">}))</span>
+</span><span id="L-1272"><a href="#L-1272"><span class="linenos">1272</span></a>                    <span class="k">else</span><span class="p">:</span>
+</span><span id="L-1273"><a href="#L-1273"><span class="linenos">1273</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;conf changed&quot;</span><span class="p">}))</span>
+</span><span id="L-1274"><a href="#L-1274"><span class="linenos">1274</span></a>                        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">conf_file</span><span class="p">:</span>
+</span><span id="L-1275"><a href="#L-1275"><span class="linenos">1275</span></a>                            <span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;conf&quot;</span><span class="p">],</span> <span class="n">conf_file</span><span class="p">)</span>
+</span><span id="L-1276"><a href="#L-1276"><span class="linenos">1276</span></a>            <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="L-1277"><a href="#L-1277"><span class="linenos">1277</span></a>                <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">callback</span><span class="p">(</span><span class="n">message</span><span class="p">))</span>
+</span><span id="L-1278"><a href="#L-1278"><span class="linenos">1278</span></a>                <span class="n">background_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="L-1279"><a href="#L-1279"><span class="linenos">1279</span></a>                <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="n">background_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="L-1280"><a href="#L-1280"><span class="linenos">1280</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">task_done</span><span class="p">()</span>
+</span><span id="L-1281"><a href="#L-1281"><span class="linenos">1281</span></a>
+</span><span id="L-1282"><a href="#L-1282"><span class="linenos">1282</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-1283"><a href="#L-1283"><span class="linenos">1283</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send a message to the message bus.</span>
+</span><span id="L-1284"><a href="#L-1284"><span class="linenos">1284</span></a>
+</span><span id="L-1285"><a href="#L-1285"><span class="linenos">1285</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="L-1286"><a href="#L-1286"><span class="linenos">1286</span></a><span class="sd">        ...     print(f&quot;Got: {message}&quot;)</span>
+</span><span id="L-1287"><a href="#L-1287"><span class="linenos">1287</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1288"><a href="#L-1288"><span class="linenos">1288</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="L-1289"><a href="#L-1289"><span class="linenos">1289</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1290"><a href="#L-1290"><span class="linenos">1290</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="L-1291"><a href="#L-1291"><span class="linenos">1291</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1292"><a href="#L-1292"><span class="linenos">1292</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="L-1293"><a href="#L-1293"><span class="linenos">1293</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1294"><a href="#L-1294"><span class="linenos">1294</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1295"><a href="#L-1295"><span class="linenos">1295</span></a><span class="sd">        ...                  [MessageTemplate({})],</span>
+</span><span id="L-1296"><a href="#L-1296"><span class="linenos">1296</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1297"><a href="#L-1297"><span class="linenos">1297</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="L-1298"><a href="#L-1298"><span class="linenos">1298</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1299"><a href="#L-1299"><span class="linenos">1299</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="L-1300"><a href="#L-1300"><span class="linenos">1300</span></a><span class="sd">        ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="L-1301"><a href="#L-1301"><span class="linenos">1301</span></a><span class="sd">        ...                     &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="L-1302"><a href="#L-1302"><span class="linenos">1302</span></a><span class="sd">        ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="L-1303"><a href="#L-1303"><span class="linenos">1303</span></a><span class="sd">        ...     try:</span>
+</span><span id="L-1304"><a href="#L-1304"><span class="linenos">1304</span></a><span class="sd">        ...         await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="L-1305"><a href="#L-1305"><span class="linenos">1305</span></a><span class="sd">        ...                         &#39;k1&#39;: 42})</span>
+</span><span id="L-1306"><a href="#L-1306"><span class="linenos">1306</span></a><span class="sd">        ...     except BusException as e:</span>
+</span><span id="L-1307"><a href="#L-1307"><span class="linenos">1307</span></a><span class="sd">        ...         print(e)</span>
+</span><span id="L-1308"><a href="#L-1308"><span class="linenos">1308</span></a><span class="sd">        ...     await asyncio.sleep(0)</span>
+</span><span id="L-1309"><a href="#L-1309"><span class="linenos">1309</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="L-1310"><a href="#L-1310"><span class="linenos">1310</span></a><span class="sd">        ...     try:</span>
+</span><span id="L-1311"><a href="#L-1311"><span class="linenos">1311</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="L-1312"><a href="#L-1312"><span class="linenos">1312</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-1313"><a href="#L-1313"><span class="linenos">1313</span></a><span class="sd">        ...         pass</span>
+</span><span id="L-1314"><a href="#L-1314"><span class="linenos">1314</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-1315"><a href="#L-1315"><span class="linenos">1315</span></a><span class="sd">        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+</span><span id="L-1316"><a href="#L-1316"><span class="linenos">1316</span></a><span class="sd">        not allowed for sender &#39;Client 1&#39;.</span>
+</span><span id="L-1317"><a href="#L-1317"><span class="linenos">1317</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="L-1318"><a href="#L-1318"><span class="linenos">1318</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="L-1319"><a href="#L-1319"><span class="linenos">1319</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1320"><a href="#L-1320"><span class="linenos">1320</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-1321"><a href="#L-1321"><span class="linenos">1321</span></a>        <span class="n">sender</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span>
+</span><span id="L-1322"><a href="#L-1322"><span class="linenos">1322</span></a>        <span class="k">if</span> <span class="n">sender</span><span class="p">:</span>
+</span><span id="L-1323"><a href="#L-1323"><span class="linenos">1323</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="L-1324"><a href="#L-1324"><span class="linenos">1324</span></a>                <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span>
+</span><span id="L-1325"><a href="#L-1325"><span class="linenos">1325</span></a>                    <span class="sa">f</span><span class="s2">&quot;Message &#39;</span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&#39; not allowed for sender &#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
+</span><span id="L-1326"><a href="#L-1326"><span class="linenos">1326</span></a>                <span class="p">)</span>
+</span><span id="L-1327"><a href="#L-1327"><span class="linenos">1327</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span><span id="L-1328"><a href="#L-1328"><span class="linenos">1328</span></a>
+</span><span id="L-1329"><a href="#L-1329"><span class="linenos">1329</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">send_nowait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-1330"><a href="#L-1330"><span class="linenos">1330</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send a message to the message bus without blocking.</span>
+</span><span id="L-1331"><a href="#L-1331"><span class="linenos">1331</span></a>
+</span><span id="L-1332"><a href="#L-1332"><span class="linenos">1332</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="L-1333"><a href="#L-1333"><span class="linenos">1333</span></a><span class="sd">        ...     print(f&quot;Got: {message}&quot;)</span>
+</span><span id="L-1334"><a href="#L-1334"><span class="linenos">1334</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="L-1335"><a href="#L-1335"><span class="linenos">1335</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="L-1336"><a href="#L-1336"><span class="linenos">1336</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1337"><a href="#L-1337"><span class="linenos">1337</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="L-1338"><a href="#L-1338"><span class="linenos">1338</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1339"><a href="#L-1339"><span class="linenos">1339</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="L-1340"><a href="#L-1340"><span class="linenos">1340</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1341"><a href="#L-1341"><span class="linenos">1341</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="L-1342"><a href="#L-1342"><span class="linenos">1342</span></a><span class="sd">        ...                  [MessageTemplate({})],</span>
+</span><span id="L-1343"><a href="#L-1343"><span class="linenos">1343</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="L-1344"><a href="#L-1344"><span class="linenos">1344</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="L-1345"><a href="#L-1345"><span class="linenos">1345</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="L-1346"><a href="#L-1346"><span class="linenos">1346</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="L-1347"><a href="#L-1347"><span class="linenos">1347</span></a><span class="sd">        ...     bus.send_nowait({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="L-1348"><a href="#L-1348"><span class="linenos">1348</span></a><span class="sd">        ...                      &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="L-1349"><a href="#L-1349"><span class="linenos">1349</span></a><span class="sd">        ...     bus.send_nowait({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="L-1350"><a href="#L-1350"><span class="linenos">1350</span></a><span class="sd">        ...     try:</span>
+</span><span id="L-1351"><a href="#L-1351"><span class="linenos">1351</span></a><span class="sd">        ...         bus.send_nowait({&#39;sender&#39;: &#39;Client 1&#39;,</span>
+</span><span id="L-1352"><a href="#L-1352"><span class="linenos">1352</span></a><span class="sd">        ...                          &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42})</span>
+</span><span id="L-1353"><a href="#L-1353"><span class="linenos">1353</span></a><span class="sd">        ...     except BusException as e:</span>
+</span><span id="L-1354"><a href="#L-1354"><span class="linenos">1354</span></a><span class="sd">        ...         print(e)</span>
+</span><span id="L-1355"><a href="#L-1355"><span class="linenos">1355</span></a><span class="sd">        ...     await asyncio.sleep(0)</span>
+</span><span id="L-1356"><a href="#L-1356"><span class="linenos">1356</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="L-1357"><a href="#L-1357"><span class="linenos">1357</span></a><span class="sd">        ...     try:</span>
+</span><span id="L-1358"><a href="#L-1358"><span class="linenos">1358</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="L-1359"><a href="#L-1359"><span class="linenos">1359</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="L-1360"><a href="#L-1360"><span class="linenos">1360</span></a><span class="sd">        ...         pass</span>
+</span><span id="L-1361"><a href="#L-1361"><span class="linenos">1361</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-1362"><a href="#L-1362"><span class="linenos">1362</span></a><span class="sd">        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+</span><span id="L-1363"><a href="#L-1363"><span class="linenos">1363</span></a><span class="sd">        not allowed for sender &#39;Client 1&#39;.</span>
+</span><span id="L-1364"><a href="#L-1364"><span class="linenos">1364</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="L-1365"><a href="#L-1365"><span class="linenos">1365</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="L-1366"><a href="#L-1366"><span class="linenos">1366</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-1367"><a href="#L-1367"><span class="linenos">1367</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-1368"><a href="#L-1368"><span class="linenos">1368</span></a>        <span class="n">sender</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span>
+</span><span id="L-1369"><a href="#L-1369"><span class="linenos">1369</span></a>        <span class="k">if</span> <span class="n">sender</span><span class="p">:</span>
+</span><span id="L-1370"><a href="#L-1370"><span class="linenos">1370</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="L-1371"><a href="#L-1371"><span class="linenos">1371</span></a>                <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span>
+</span><span id="L-1372"><a href="#L-1372"><span class="linenos">1372</span></a>                    <span class="sa">f</span><span class="s2">&quot;Message &#39;</span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&#39; not allowed for sender &#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
+</span><span id="L-1373"><a href="#L-1373"><span class="linenos">1373</span></a>                <span class="p">)</span>
+</span><span id="L-1374"><a href="#L-1374"><span class="linenos">1374</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="MessageValue">
+                    <div class="attr variable">
+            <span class="name">MessageValue</span>        =
+<span class="default_value">None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]</span>
+
+        
+    </div>
+    <a class="headerlink" href="#MessageValue"></a>
+    
+    
+
+                </section>
+                <section id="JSONSchema">
+                    <div class="attr variable">
+            <span class="name">JSONSchema</span>        =
+<input id="JSONSchema-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="JSONSchema-view-value"></label><span class="default_value">bool | typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]</span>
+
+        
+    </div>
+    <a class="headerlink" href="#JSONSchema"></a>
+    
+    
+
+                </section>
+                <section id="MessageCallback">
+                    <div class="attr variable">
+            <span class="name">MessageCallback</span>        =
+<span class="default_value">typing.Callable[[ForwardRef(&#39;Message&#39;)], typing.Coroutine[typing.Any, typing.Any, NoneType]]</span>
+
+        
+    </div>
+    <a class="headerlink" href="#MessageCallback"></a>
+    
+    
+
+                </section>
+                <section id="register_schema">
+                            <input id="register_schema-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">register_schema</span><span class="signature pdoc-code multiline">(<span class="param">     <span class="n">schema</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]</span></span><span class="return-annotation">) -> <span class="nb">bool</span>:</span></span>
+
+                <label class="view-source-button" for="register_schema-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#register_schema"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="register_schema-122"><a href="#register_schema-122"><span class="linenos">122</span></a><span class="k">def</span><span class="w"> </span><span class="nf">register_schema</span><span class="p">(</span><span class="n">schema</span><span class="p">:</span> <span class="n">JSONSchema</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="register_schema-123"><a href="#register_schema-123"><span class="linenos">123</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Register the given JSON schema in the global cache.&quot;&quot;&quot;</span>
+</span><span id="register_schema-124"><a href="#register_schema-124"><span class="linenos">124</span></a>    <span class="k">global</span> <span class="n">_validates</span>
+</span><span id="register_schema-125"><a href="#register_schema-125"><span class="linenos">125</span></a>    <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="register_schema-126"><a href="#register_schema-126"><span class="linenos">126</span></a>    <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_validates</span><span class="p">:</span>
+</span><span id="register_schema-127"><a href="#register_schema-127"><span class="linenos">127</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)):</span>
+</span><span id="register_schema-128"><a href="#register_schema-128"><span class="linenos">128</span></a>            <span class="k">return</span> <span class="kc">False</span>
+</span><span id="register_schema-129"><a href="#register_schema-129"><span class="linenos">129</span></a>        <span class="k">try</span><span class="p">:</span>
+</span><span id="register_schema-130"><a href="#register_schema-130"><span class="linenos">130</span></a>            <span class="n">_validates</span><span class="p">[</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="register_schema-131"><a href="#register_schema-131"><span class="linenos">131</span></a>        <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaDefinitionException</span><span class="p">:</span>
+</span><span id="register_schema-132"><a href="#register_schema-132"><span class="linenos">132</span></a>            <span class="k">return</span> <span class="kc">False</span>
+</span><span id="register_schema-133"><a href="#register_schema-133"><span class="linenos">133</span></a>    <span class="k">return</span> <span class="kc">True</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register the given JSON schema in the global cache.</p>
+</div>
+
+
+                </section>
+                <section id="validate">
+                            <input id="validate-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">validate</span><span class="signature pdoc-code multiline">(<span class="param">    <span class="n">schema_string</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">    <span class="n">value</span><span class="p">:</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span></span><span class="return-annotation">) -> <span class="nb">bool</span>:</span></span>
+
+                <label class="view-source-button" for="validate-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#validate"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="validate-136"><a href="#validate-136"><span class="linenos">136</span></a><span class="k">def</span><span class="w"> </span><span class="nf">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="validate-137"><a href="#validate-137"><span class="linenos">137</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Validate the given MessageValue against the given JSON schema string.&quot;&quot;&quot;</span>
+</span><span id="validate-138"><a href="#validate-138"><span class="linenos">138</span></a>    <span class="k">global</span> <span class="n">_validates</span>
+</span><span id="validate-139"><a href="#validate-139"><span class="linenos">139</span></a>    <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_validates</span><span class="p">:</span>
+</span><span id="validate-140"><a href="#validate-140"><span class="linenos">140</span></a>        <span class="n">schema</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">schema_string</span><span class="p">)</span>
+</span><span id="validate-141"><a href="#validate-141"><span class="linenos">141</span></a>        <span class="n">_validates</span><span class="p">[</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="validate-142"><a href="#validate-142"><span class="linenos">142</span></a>    <span class="n">validate</span> <span class="o">=</span> <span class="n">_validates</span><span class="p">[</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="validate-143"><a href="#validate-143"><span class="linenos">143</span></a>    <span class="k">try</span><span class="p">:</span>
+</span><span id="validate-144"><a href="#validate-144"><span class="linenos">144</span></a>        <span class="n">validate</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+</span><span id="validate-145"><a href="#validate-145"><span class="linenos">145</span></a>    <span class="k">except</span> <span class="n">fastjsonschema</span><span class="o">.</span><span class="n">JsonSchemaException</span><span class="p">:</span>
+</span><span id="validate-146"><a href="#validate-146"><span class="linenos">146</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="validate-147"><a href="#validate-147"><span class="linenos">147</span></a>    <span class="k">return</span> <span class="kc">True</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Validate the given MessageValue against the given JSON schema string.</p>
+</div>
+
+
+                </section>
+                <section id="Message">
+                            <input id="Message-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Message</span><wbr>(<span class="base">typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]</span>):
+
+                <label class="view-source-button" for="Message-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Message"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Message-150"><a href="#Message-150"><span class="linenos">150</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Message</span><span class="p">(</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MessageValue</span><span class="p">]):</span>
+</span><span id="Message-151"><a href="#Message-151"><span class="linenos">151</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define arbitrary message.</span>
+</span><span id="Message-152"><a href="#Message-152"><span class="linenos">152</span></a>
+</span><span id="Message-153"><a href="#Message-153"><span class="linenos">153</span></a><span class="sd">    Messages are dictionaries with string keys and values that are strings,</span>
+</span><span id="Message-154"><a href="#Message-154"><span class="linenos">154</span></a><span class="sd">    integers, floats, Booleans, dictionaries that recursively have string</span>
+</span><span id="Message-155"><a href="#Message-155"><span class="linenos">155</span></a><span class="sd">    keys and values of any of these types, or lists with elements that have</span>
+</span><span id="Message-156"><a href="#Message-156"><span class="linenos">156</span></a><span class="sd">    any of these types. These constraints are checked when setting key-value</span>
+</span><span id="Message-157"><a href="#Message-157"><span class="linenos">157</span></a><span class="sd">    pairs of the message.</span>
+</span><span id="Message-158"><a href="#Message-158"><span class="linenos">158</span></a>
+</span><span id="Message-159"><a href="#Message-159"><span class="linenos">159</span></a><span class="sd">    A message has to have a sender, which is set by the constructor:</span>
+</span><span id="Message-160"><a href="#Message-160"><span class="linenos">160</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message-161"><a href="#Message-161"><span class="linenos">161</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-162"><a href="#Message-162"><span class="linenos">162</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;}</span>
+</span><span id="Message-163"><a href="#Message-163"><span class="linenos">163</span></a>
+</span><span id="Message-164"><a href="#Message-164"><span class="linenos">164</span></a><span class="sd">    A dictionary can be given to the constructor:</span>
+</span><span id="Message-165"><a href="#Message-165"><span class="linenos">165</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;,</span>
+</span><span id="Message-166"><a href="#Message-166"><span class="linenos">166</span></a><span class="sd">    ...             {&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})</span>
+</span><span id="Message-167"><a href="#Message-167"><span class="linenos">167</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-168"><a href="#Message-168"><span class="linenos">168</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="Message-169"><a href="#Message-169"><span class="linenos">169</span></a>
+</span><span id="Message-170"><a href="#Message-170"><span class="linenos">170</span></a><span class="sd">    A &#39;sender&#39; set in the initial dictionary is overwritten by the explicitly</span>
+</span><span id="Message-171"><a href="#Message-171"><span class="linenos">171</span></a><span class="sd">    given sender in the first argument:</span>
+</span><span id="Message-172"><a href="#Message-172"><span class="linenos">172</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;,</span>
+</span><span id="Message-173"><a href="#Message-173"><span class="linenos">173</span></a><span class="sd">    ...             {&#39;sender&#39;: &#39;Original sender&#39;, &#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="Message-174"><a href="#Message-174"><span class="linenos">174</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-175"><a href="#Message-175"><span class="linenos">175</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="Message-176"><a href="#Message-176"><span class="linenos">176</span></a>
+</span><span id="Message-177"><a href="#Message-177"><span class="linenos">177</span></a><span class="sd">    Or the message can be modified after construction:</span>
+</span><span id="Message-178"><a href="#Message-178"><span class="linenos">178</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})</span>
+</span><span id="Message-179"><a href="#Message-179"><span class="linenos">179</span></a><span class="sd">    &gt;&gt;&gt; m[&#39;key 2&#39;] = &#39;value 2&#39;</span>
+</span><span id="Message-180"><a href="#Message-180"><span class="linenos">180</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-181"><a href="#Message-181"><span class="linenos">181</span></a><span class="sd">    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="Message-182"><a href="#Message-182"><span class="linenos">182</span></a>
+</span><span id="Message-183"><a href="#Message-183"><span class="linenos">183</span></a><span class="sd">    The &#39;sender&#39; key can be overwritten, but this should only be done in</span>
+</span><span id="Message-184"><a href="#Message-184"><span class="linenos">184</span></a><span class="sd">    exceptional cases:</span>
+</span><span id="Message-185"><a href="#Message-185"><span class="linenos">185</span></a><span class="sd">    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="Message-186"><a href="#Message-186"><span class="linenos">186</span></a><span class="sd">    &gt;&gt;&gt; m[&#39;sender&#39;] = &#39;New sender&#39;</span>
+</span><span id="Message-187"><a href="#Message-187"><span class="linenos">187</span></a><span class="sd">    &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-188"><a href="#Message-188"><span class="linenos">188</span></a><span class="sd">    {&#39;sender&#39;: &#39;New sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="Message-189"><a href="#Message-189"><span class="linenos">189</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Message-190"><a href="#Message-190"><span class="linenos">190</span></a>
+</span><span id="Message-191"><a href="#Message-191"><span class="linenos">191</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
+</span><span id="Message-192"><a href="#Message-192"><span class="linenos">192</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">sender</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">init</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MessageValue</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
+</span><span id="Message-193"><a href="#Message-193"><span class="linenos">193</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message-194"><a href="#Message-194"><span class="linenos">194</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise message.</span>
+</span><span id="Message-195"><a href="#Message-195"><span class="linenos">195</span></a>
+</span><span id="Message-196"><a href="#Message-196"><span class="linenos">196</span></a><span class="sd">        Message is initialised with given sender and possibly given</span>
+</span><span id="Message-197"><a href="#Message-197"><span class="linenos">197</span></a><span class="sd">        key-value pairs:</span>
+</span><span id="Message-198"><a href="#Message-198"><span class="linenos">198</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message-199"><a href="#Message-199"><span class="linenos">199</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-200"><a href="#Message-200"><span class="linenos">200</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;}</span>
+</span><span id="Message-201"><a href="#Message-201"><span class="linenos">201</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})</span>
+</span><span id="Message-202"><a href="#Message-202"><span class="linenos">202</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-203"><a href="#Message-203"><span class="linenos">203</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}</span>
+</span><span id="Message-204"><a href="#Message-204"><span class="linenos">204</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message-205"><a href="#Message-205"><span class="linenos">205</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="Message-206"><a href="#Message-206"><span class="linenos">206</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39; is not a valid sender name (not a string).&quot;</span><span class="p">)</span>
+</span><span id="Message-207"><a href="#Message-207"><span class="linenos">207</span></a>        <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+</span><span id="Message-208"><a href="#Message-208"><span class="linenos">208</span></a>        <span class="k">if</span> <span class="n">init</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message-209"><a href="#Message-209"><span class="linenos">209</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">init</span><span class="p">)</span>
+</span><span id="Message-210"><a href="#Message-210"><span class="linenos">210</span></a>        <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">sender</span>
+</span><span id="Message-211"><a href="#Message-211"><span class="linenos">211</span></a>
+</span><span id="Message-212"><a href="#Message-212"><span class="linenos">212</span></a>    <span class="nd">@staticmethod</span>
+</span><span id="Message-213"><a href="#Message-213"><span class="linenos">213</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="Message-214"><a href="#Message-214"><span class="linenos">214</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check recursively if a given value is valid.</span>
+</span><span id="Message-215"><a href="#Message-215"><span class="linenos">215</span></a>
+</span><span id="Message-216"><a href="#Message-216"><span class="linenos">216</span></a><span class="sd">        None, strings, integers, floats and Booleans are valid:</span>
+</span><span id="Message-217"><a href="#Message-217"><span class="linenos">217</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(None)</span>
+</span><span id="Message-218"><a href="#Message-218"><span class="linenos">218</span></a><span class="sd">        True</span>
+</span><span id="Message-219"><a href="#Message-219"><span class="linenos">219</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(&#39;Spam&#39;)</span>
+</span><span id="Message-220"><a href="#Message-220"><span class="linenos">220</span></a><span class="sd">        True</span>
+</span><span id="Message-221"><a href="#Message-221"><span class="linenos">221</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(42)</span>
+</span><span id="Message-222"><a href="#Message-222"><span class="linenos">222</span></a><span class="sd">        True</span>
+</span><span id="Message-223"><a href="#Message-223"><span class="linenos">223</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(42.42)</span>
+</span><span id="Message-224"><a href="#Message-224"><span class="linenos">224</span></a><span class="sd">        True</span>
+</span><span id="Message-225"><a href="#Message-225"><span class="linenos">225</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(False)</span>
+</span><span id="Message-226"><a href="#Message-226"><span class="linenos">226</span></a><span class="sd">        True</span>
+</span><span id="Message-227"><a href="#Message-227"><span class="linenos">227</span></a>
+</span><span id="Message-228"><a href="#Message-228"><span class="linenos">228</span></a><span class="sd">        Other basic types are not valid:</span>
+</span><span id="Message-229"><a href="#Message-229"><span class="linenos">229</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(b&#39;bytes&#39;)</span>
+</span><span id="Message-230"><a href="#Message-230"><span class="linenos">230</span></a><span class="sd">        False</span>
+</span><span id="Message-231"><a href="#Message-231"><span class="linenos">231</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(1j)</span>
+</span><span id="Message-232"><a href="#Message-232"><span class="linenos">232</span></a><span class="sd">        False</span>
+</span><span id="Message-233"><a href="#Message-233"><span class="linenos">233</span></a>
+</span><span id="Message-234"><a href="#Message-234"><span class="linenos">234</span></a><span class="sd">        Dictionaries with string keys and recursively valid values are valid:</span>
+</span><span id="Message-235"><a href="#Message-235"><span class="linenos">235</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({&#39;str value&#39;: &#39;Spam&#39;, &#39;int value&#39;: 42,</span>
+</span><span id="Message-236"><a href="#Message-236"><span class="linenos">236</span></a><span class="sd">        ...                      &#39;float value&#39;: 42.42, &#39;bool value&#39;: False})</span>
+</span><span id="Message-237"><a href="#Message-237"><span class="linenos">237</span></a><span class="sd">        True</span>
+</span><span id="Message-238"><a href="#Message-238"><span class="linenos">238</span></a>
+</span><span id="Message-239"><a href="#Message-239"><span class="linenos">239</span></a><span class="sd">        Empty dictionaries are valid:</span>
+</span><span id="Message-240"><a href="#Message-240"><span class="linenos">240</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({})</span>
+</span><span id="Message-241"><a href="#Message-241"><span class="linenos">241</span></a><span class="sd">        True</span>
+</span><span id="Message-242"><a href="#Message-242"><span class="linenos">242</span></a>
+</span><span id="Message-243"><a href="#Message-243"><span class="linenos">243</span></a><span class="sd">        Dictionaries with other keys are not valid:</span>
+</span><span id="Message-244"><a href="#Message-244"><span class="linenos">244</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({42: &#39;int key&#39;})</span>
+</span><span id="Message-245"><a href="#Message-245"><span class="linenos">245</span></a><span class="sd">        False</span>
+</span><span id="Message-246"><a href="#Message-246"><span class="linenos">246</span></a>
+</span><span id="Message-247"><a href="#Message-247"><span class="linenos">247</span></a><span class="sd">        Dictionaries with invalid values are not valid:</span>
+</span><span id="Message-248"><a href="#Message-248"><span class="linenos">248</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({&#39;complex value&#39;: 1j})</span>
+</span><span id="Message-249"><a href="#Message-249"><span class="linenos">249</span></a><span class="sd">        False</span>
+</span><span id="Message-250"><a href="#Message-250"><span class="linenos">250</span></a>
+</span><span id="Message-251"><a href="#Message-251"><span class="linenos">251</span></a><span class="sd">        Lists with valid elements are valid:</span>
+</span><span id="Message-252"><a href="#Message-252"><span class="linenos">252</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([&#39;Spam&#39;, 42, 42.42, False])</span>
+</span><span id="Message-253"><a href="#Message-253"><span class="linenos">253</span></a><span class="sd">        True</span>
+</span><span id="Message-254"><a href="#Message-254"><span class="linenos">254</span></a>
+</span><span id="Message-255"><a href="#Message-255"><span class="linenos">255</span></a><span class="sd">        Empty lists are valid:</span>
+</span><span id="Message-256"><a href="#Message-256"><span class="linenos">256</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([])</span>
+</span><span id="Message-257"><a href="#Message-257"><span class="linenos">257</span></a><span class="sd">        True</span>
+</span><span id="Message-258"><a href="#Message-258"><span class="linenos">258</span></a>
+</span><span id="Message-259"><a href="#Message-259"><span class="linenos">259</span></a><span class="sd">        Lists with invalid elements are not valid:</span>
+</span><span id="Message-260"><a href="#Message-260"><span class="linenos">260</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([1j])</span>
+</span><span id="Message-261"><a href="#Message-261"><span class="linenos">261</span></a><span class="sd">        False</span>
+</span><span id="Message-262"><a href="#Message-262"><span class="linenos">262</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message-263"><a href="#Message-263"><span class="linenos">263</span></a>        <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message-264"><a href="#Message-264"><span class="linenos">264</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message-265"><a href="#Message-265"><span class="linenos">265</span></a>        <span class="k">elif</span> <span class="p">(</span>
+</span><span id="Message-266"><a href="#Message-266"><span class="linenos">266</span></a>            <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="Message-267"><a href="#Message-267"><span class="linenos">267</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
+</span><span id="Message-268"><a href="#Message-268"><span class="linenos">268</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
+</span><span id="Message-269"><a href="#Message-269"><span class="linenos">269</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="Message-270"><a href="#Message-270"><span class="linenos">270</span></a>        <span class="p">):</span>
+</span><span id="Message-271"><a href="#Message-271"><span class="linenos">271</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message-272"><a href="#Message-272"><span class="linenos">272</span></a>        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+</span><span id="Message-273"><a href="#Message-273"><span class="linenos">273</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="Message-274"><a href="#Message-274"><span class="linenos">274</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="Message-275"><a href="#Message-275"><span class="linenos">275</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message-276"><a href="#Message-276"><span class="linenos">276</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">Message</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="Message-277"><a href="#Message-277"><span class="linenos">277</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message-278"><a href="#Message-278"><span class="linenos">278</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message-279"><a href="#Message-279"><span class="linenos">279</span></a>        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="Message-280"><a href="#Message-280"><span class="linenos">280</span></a>            <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="Message-281"><a href="#Message-281"><span class="linenos">281</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">Message</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">element</span><span class="p">):</span>
+</span><span id="Message-282"><a href="#Message-282"><span class="linenos">282</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message-283"><a href="#Message-283"><span class="linenos">283</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message-284"><a href="#Message-284"><span class="linenos">284</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message-285"><a href="#Message-285"><span class="linenos">285</span></a>
+</span><span id="Message-286"><a href="#Message-286"><span class="linenos">286</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message-287"><a href="#Message-287"><span class="linenos">287</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check key and value before putting pair into dict.</span>
+</span><span id="Message-288"><a href="#Message-288"><span class="linenos">288</span></a>
+</span><span id="Message-289"><a href="#Message-289"><span class="linenos">289</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message-290"><a href="#Message-290"><span class="linenos">290</span></a><span class="sd">        &gt;&gt;&gt; m[&#39;key&#39;] = &#39;value&#39;</span>
+</span><span id="Message-291"><a href="#Message-291"><span class="linenos">291</span></a><span class="sd">        &gt;&gt;&gt; m[&#39;dict&#39;] = {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}</span>
+</span><span id="Message-292"><a href="#Message-292"><span class="linenos">292</span></a><span class="sd">        &gt;&gt;&gt; print(m)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Message-293"><a href="#Message-293"><span class="linenos">293</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;,</span>
+</span><span id="Message-294"><a href="#Message-294"><span class="linenos">294</span></a><span class="sd">         &#39;dict&#39;: {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}}</span>
+</span><span id="Message-295"><a href="#Message-295"><span class="linenos">295</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message-296"><a href="#Message-296"><span class="linenos">296</span></a><span class="sd">        &gt;&gt;&gt; m[42] = &#39;int key&#39;</span>
+</span><span id="Message-297"><a href="#Message-297"><span class="linenos">297</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-298"><a href="#Message-298"><span class="linenos">298</span></a><span class="sd">          ...</span>
+</span><span id="Message-299"><a href="#Message-299"><span class="linenos">299</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message-300"><a href="#Message-300"><span class="linenos">300</span></a><span class="sd">        &gt;&gt;&gt; m[&#39;complex value&#39;] = 1j</span>
+</span><span id="Message-301"><a href="#Message-301"><span class="linenos">301</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-302"><a href="#Message-302"><span class="linenos">302</span></a><span class="sd">          ...</span>
+</span><span id="Message-303"><a href="#Message-303"><span class="linenos">303</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message-304"><a href="#Message-304"><span class="linenos">304</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message-305"><a href="#Message-305"><span class="linenos">305</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="Message-306"><a href="#Message-306"><span class="linenos">306</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2">&#39; is not a valid key in Message (not a string).&quot;</span><span class="p">)</span>
+</span><span id="Message-307"><a href="#Message-307"><span class="linenos">307</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
+</span><span id="Message-308"><a href="#Message-308"><span class="linenos">308</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">&#39; is not a valid value in Message.&quot;</span><span class="p">)</span>
+</span><span id="Message-309"><a href="#Message-309"><span class="linenos">309</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+</span><span id="Message-310"><a href="#Message-310"><span class="linenos">310</span></a>
+</span><span id="Message-311"><a href="#Message-311"><span class="linenos">311</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message-312"><a href="#Message-312"><span class="linenos">312</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override update to use validity checks.</span>
+</span><span id="Message-313"><a href="#Message-313"><span class="linenos">313</span></a>
+</span><span id="Message-314"><a href="#Message-314"><span class="linenos">314</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message-315"><a href="#Message-315"><span class="linenos">315</span></a><span class="sd">        &gt;&gt;&gt; m.update({&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})</span>
+</span><span id="Message-316"><a href="#Message-316"><span class="linenos">316</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-317"><a href="#Message-317"><span class="linenos">317</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="Message-318"><a href="#Message-318"><span class="linenos">318</span></a><span class="sd">        &gt;&gt;&gt; m.update({42: &#39;int key&#39;})</span>
+</span><span id="Message-319"><a href="#Message-319"><span class="linenos">319</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-320"><a href="#Message-320"><span class="linenos">320</span></a><span class="sd">          ...</span>
+</span><span id="Message-321"><a href="#Message-321"><span class="linenos">321</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message-322"><a href="#Message-322"><span class="linenos">322</span></a><span class="sd">        &gt;&gt;&gt; m.update({&#39;complex value&#39;: 1j})</span>
+</span><span id="Message-323"><a href="#Message-323"><span class="linenos">323</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-324"><a href="#Message-324"><span class="linenos">324</span></a><span class="sd">          ...</span>
+</span><span id="Message-325"><a href="#Message-325"><span class="linenos">325</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message-326"><a href="#Message-326"><span class="linenos">326</span></a>
+</span><span id="Message-327"><a href="#Message-327"><span class="linenos">327</span></a><span class="sd">        This is also used in __init__:</span>
+</span><span id="Message-328"><a href="#Message-328"><span class="linenos">328</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="Message-329"><a href="#Message-329"><span class="linenos">329</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message-330"><a href="#Message-330"><span class="linenos">330</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="Message-331"><a href="#Message-331"><span class="linenos">331</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {42: &#39;int key&#39;})</span>
+</span><span id="Message-332"><a href="#Message-332"><span class="linenos">332</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-333"><a href="#Message-333"><span class="linenos">333</span></a><span class="sd">          ...</span>
+</span><span id="Message-334"><a href="#Message-334"><span class="linenos">334</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message-335"><a href="#Message-335"><span class="linenos">335</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;complex value&#39;: 1j})</span>
+</span><span id="Message-336"><a href="#Message-336"><span class="linenos">336</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-337"><a href="#Message-337"><span class="linenos">337</span></a><span class="sd">          ...</span>
+</span><span id="Message-338"><a href="#Message-338"><span class="linenos">338</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message-339"><a href="#Message-339"><span class="linenos">339</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message-340"><a href="#Message-340"><span class="linenos">340</span></a>        <span class="k">if</span> <span class="n">args</span><span class="p">:</span>
+</span><span id="Message-341"><a href="#Message-341"><span class="linenos">341</span></a>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+</span><span id="Message-342"><a href="#Message-342"><span class="linenos">342</span></a>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;update expected at most 1 argument, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="Message-343"><a href="#Message-343"><span class="linenos">343</span></a>            <span class="n">other</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</span><span id="Message-344"><a href="#Message-344"><span class="linenos">344</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">other</span><span class="p">:</span>
+</span><span id="Message-345"><a href="#Message-345"><span class="linenos">345</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">other</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="Message-346"><a href="#Message-346"><span class="linenos">346</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
+</span><span id="Message-347"><a href="#Message-347"><span class="linenos">347</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="Message-348"><a href="#Message-348"><span class="linenos">348</span></a>
+</span><span id="Message-349"><a href="#Message-349"><span class="linenos">349</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MessageValue</span><span class="p">:</span>
+</span><span id="Message-350"><a href="#Message-350"><span class="linenos">350</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override setdefault to use validity checks.</span>
+</span><span id="Message-351"><a href="#Message-351"><span class="linenos">351</span></a>
+</span><span id="Message-352"><a href="#Message-352"><span class="linenos">352</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message-353"><a href="#Message-353"><span class="linenos">353</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 1&#39;)</span>
+</span><span id="Message-354"><a href="#Message-354"><span class="linenos">354</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="Message-355"><a href="#Message-355"><span class="linenos">355</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 2&#39;)</span>
+</span><span id="Message-356"><a href="#Message-356"><span class="linenos">356</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="Message-357"><a href="#Message-357"><span class="linenos">357</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(42, &#39;int key&#39;)</span>
+</span><span id="Message-358"><a href="#Message-358"><span class="linenos">358</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-359"><a href="#Message-359"><span class="linenos">359</span></a><span class="sd">          ...</span>
+</span><span id="Message-360"><a href="#Message-360"><span class="linenos">360</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message-361"><a href="#Message-361"><span class="linenos">361</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;complex value&#39;, 1j)</span>
+</span><span id="Message-362"><a href="#Message-362"><span class="linenos">362</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message-363"><a href="#Message-363"><span class="linenos">363</span></a><span class="sd">          ...</span>
+</span><span id="Message-364"><a href="#Message-364"><span class="linenos">364</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message-365"><a href="#Message-365"><span class="linenos">365</span></a>
+</span><span id="Message-366"><a href="#Message-366"><span class="linenos">366</span></a><span class="sd">        But __setitem__ is not called if the key is already present:</span>
+</span><span id="Message-367"><a href="#Message-367"><span class="linenos">367</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, 1j)</span>
+</span><span id="Message-368"><a href="#Message-368"><span class="linenos">368</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="Message-369"><a href="#Message-369"><span class="linenos">369</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message-370"><a href="#Message-370"><span class="linenos">370</span></a>        <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="Message-371"><a href="#Message-371"><span class="linenos">371</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="Message-372"><a href="#Message-372"><span class="linenos">372</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Define arbitrary message.</p>
+
+<p>Messages are dictionaries with string keys and values that are strings,
+integers, floats, Booleans, dictionaries that recursively have string
+keys and values of any of these types, or lists with elements that have
+any of these types. These constraints are checked when setting key-value
+pairs of the message.</p>
+
+<p>A message has to have a sender, which is set by the constructor:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;}</span>
+</code></pre>
+</div>
+
+<p>A dictionary can be given to the constructor:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>            <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value 1&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;value 2&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</code></pre>
+</div>
+
+<p>A 'sender' set in the initial dictionary is overwritten by the explicitly
+given sender in the first argument:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>            <span class="p">{</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Original sender&#39;</span><span class="p">,</span> <span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</code></pre>
+</div>
+
+<p>Or the message can be modified after construction:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value 1&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="p">[</span><span class="s1">&#39;key 2&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;value 2&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</code></pre>
+</div>
+
+<p>The 'sender' key can be overwritten, but this should only be done in
+exceptional cases:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="p">[</span><span class="s1">&#39;sender&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;New sender&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;New sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Message.__init__" class="classattr">
+                                        <input id="Message.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="name">Message</span><span class="signature pdoc-code multiline">(<span class="param">     <span class="n">sender</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">   <span class="n">init</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span></span>)</span>
+
+                <label class="view-source-button" for="Message.__init__-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Message.__init__"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Message.__init__-191"><a href="#Message.__init__-191"><span class="linenos">191</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
+</span><span id="Message.__init__-192"><a href="#Message.__init__-192"><span class="linenos">192</span></a>        <span class="bp">self</span><span class="p">,</span> <span class="n">sender</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">init</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MessageValue</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
+</span><span id="Message.__init__-193"><a href="#Message.__init__-193"><span class="linenos">193</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message.__init__-194"><a href="#Message.__init__-194"><span class="linenos">194</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise message.</span>
+</span><span id="Message.__init__-195"><a href="#Message.__init__-195"><span class="linenos">195</span></a>
+</span><span id="Message.__init__-196"><a href="#Message.__init__-196"><span class="linenos">196</span></a><span class="sd">        Message is initialised with given sender and possibly given</span>
+</span><span id="Message.__init__-197"><a href="#Message.__init__-197"><span class="linenos">197</span></a><span class="sd">        key-value pairs:</span>
+</span><span id="Message.__init__-198"><a href="#Message.__init__-198"><span class="linenos">198</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message.__init__-199"><a href="#Message.__init__-199"><span class="linenos">199</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message.__init__-200"><a href="#Message.__init__-200"><span class="linenos">200</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;}</span>
+</span><span id="Message.__init__-201"><a href="#Message.__init__-201"><span class="linenos">201</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})</span>
+</span><span id="Message.__init__-202"><a href="#Message.__init__-202"><span class="linenos">202</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message.__init__-203"><a href="#Message.__init__-203"><span class="linenos">203</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}</span>
+</span><span id="Message.__init__-204"><a href="#Message.__init__-204"><span class="linenos">204</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message.__init__-205"><a href="#Message.__init__-205"><span class="linenos">205</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="Message.__init__-206"><a href="#Message.__init__-206"><span class="linenos">206</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39; is not a valid sender name (not a string).&quot;</span><span class="p">)</span>
+</span><span id="Message.__init__-207"><a href="#Message.__init__-207"><span class="linenos">207</span></a>        <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+</span><span id="Message.__init__-208"><a href="#Message.__init__-208"><span class="linenos">208</span></a>        <span class="k">if</span> <span class="n">init</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message.__init__-209"><a href="#Message.__init__-209"><span class="linenos">209</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">init</span><span class="p">)</span>
+</span><span id="Message.__init__-210"><a href="#Message.__init__-210"><span class="linenos">210</span></a>        <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">sender</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Initialise message.</p>
+
+<p>Message is initialised with given sender and possibly given
+key-value pairs:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value 1&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="Message.check_value" class="classattr">
+                                        <input id="Message.check_value-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+                    <div class="decorator decorator-staticmethod">@staticmethod</div>
+
+        <span class="def">def</span>
+        <span class="name">check_value</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="n">value</span><span class="p">:</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span></span><span class="return-annotation">) -> <span class="nb">bool</span>:</span></span>
+
+                <label class="view-source-button" for="Message.check_value-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Message.check_value"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Message.check_value-212"><a href="#Message.check_value-212"><span class="linenos">212</span></a>    <span class="nd">@staticmethod</span>
+</span><span id="Message.check_value-213"><a href="#Message.check_value-213"><span class="linenos">213</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="Message.check_value-214"><a href="#Message.check_value-214"><span class="linenos">214</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check recursively if a given value is valid.</span>
+</span><span id="Message.check_value-215"><a href="#Message.check_value-215"><span class="linenos">215</span></a>
+</span><span id="Message.check_value-216"><a href="#Message.check_value-216"><span class="linenos">216</span></a><span class="sd">        None, strings, integers, floats and Booleans are valid:</span>
+</span><span id="Message.check_value-217"><a href="#Message.check_value-217"><span class="linenos">217</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(None)</span>
+</span><span id="Message.check_value-218"><a href="#Message.check_value-218"><span class="linenos">218</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-219"><a href="#Message.check_value-219"><span class="linenos">219</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(&#39;Spam&#39;)</span>
+</span><span id="Message.check_value-220"><a href="#Message.check_value-220"><span class="linenos">220</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-221"><a href="#Message.check_value-221"><span class="linenos">221</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(42)</span>
+</span><span id="Message.check_value-222"><a href="#Message.check_value-222"><span class="linenos">222</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-223"><a href="#Message.check_value-223"><span class="linenos">223</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(42.42)</span>
+</span><span id="Message.check_value-224"><a href="#Message.check_value-224"><span class="linenos">224</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-225"><a href="#Message.check_value-225"><span class="linenos">225</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(False)</span>
+</span><span id="Message.check_value-226"><a href="#Message.check_value-226"><span class="linenos">226</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-227"><a href="#Message.check_value-227"><span class="linenos">227</span></a>
+</span><span id="Message.check_value-228"><a href="#Message.check_value-228"><span class="linenos">228</span></a><span class="sd">        Other basic types are not valid:</span>
+</span><span id="Message.check_value-229"><a href="#Message.check_value-229"><span class="linenos">229</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(b&#39;bytes&#39;)</span>
+</span><span id="Message.check_value-230"><a href="#Message.check_value-230"><span class="linenos">230</span></a><span class="sd">        False</span>
+</span><span id="Message.check_value-231"><a href="#Message.check_value-231"><span class="linenos">231</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value(1j)</span>
+</span><span id="Message.check_value-232"><a href="#Message.check_value-232"><span class="linenos">232</span></a><span class="sd">        False</span>
+</span><span id="Message.check_value-233"><a href="#Message.check_value-233"><span class="linenos">233</span></a>
+</span><span id="Message.check_value-234"><a href="#Message.check_value-234"><span class="linenos">234</span></a><span class="sd">        Dictionaries with string keys and recursively valid values are valid:</span>
+</span><span id="Message.check_value-235"><a href="#Message.check_value-235"><span class="linenos">235</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({&#39;str value&#39;: &#39;Spam&#39;, &#39;int value&#39;: 42,</span>
+</span><span id="Message.check_value-236"><a href="#Message.check_value-236"><span class="linenos">236</span></a><span class="sd">        ...                      &#39;float value&#39;: 42.42, &#39;bool value&#39;: False})</span>
+</span><span id="Message.check_value-237"><a href="#Message.check_value-237"><span class="linenos">237</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-238"><a href="#Message.check_value-238"><span class="linenos">238</span></a>
+</span><span id="Message.check_value-239"><a href="#Message.check_value-239"><span class="linenos">239</span></a><span class="sd">        Empty dictionaries are valid:</span>
+</span><span id="Message.check_value-240"><a href="#Message.check_value-240"><span class="linenos">240</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({})</span>
+</span><span id="Message.check_value-241"><a href="#Message.check_value-241"><span class="linenos">241</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-242"><a href="#Message.check_value-242"><span class="linenos">242</span></a>
+</span><span id="Message.check_value-243"><a href="#Message.check_value-243"><span class="linenos">243</span></a><span class="sd">        Dictionaries with other keys are not valid:</span>
+</span><span id="Message.check_value-244"><a href="#Message.check_value-244"><span class="linenos">244</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({42: &#39;int key&#39;})</span>
+</span><span id="Message.check_value-245"><a href="#Message.check_value-245"><span class="linenos">245</span></a><span class="sd">        False</span>
+</span><span id="Message.check_value-246"><a href="#Message.check_value-246"><span class="linenos">246</span></a>
+</span><span id="Message.check_value-247"><a href="#Message.check_value-247"><span class="linenos">247</span></a><span class="sd">        Dictionaries with invalid values are not valid:</span>
+</span><span id="Message.check_value-248"><a href="#Message.check_value-248"><span class="linenos">248</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value({&#39;complex value&#39;: 1j})</span>
+</span><span id="Message.check_value-249"><a href="#Message.check_value-249"><span class="linenos">249</span></a><span class="sd">        False</span>
+</span><span id="Message.check_value-250"><a href="#Message.check_value-250"><span class="linenos">250</span></a>
+</span><span id="Message.check_value-251"><a href="#Message.check_value-251"><span class="linenos">251</span></a><span class="sd">        Lists with valid elements are valid:</span>
+</span><span id="Message.check_value-252"><a href="#Message.check_value-252"><span class="linenos">252</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([&#39;Spam&#39;, 42, 42.42, False])</span>
+</span><span id="Message.check_value-253"><a href="#Message.check_value-253"><span class="linenos">253</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-254"><a href="#Message.check_value-254"><span class="linenos">254</span></a>
+</span><span id="Message.check_value-255"><a href="#Message.check_value-255"><span class="linenos">255</span></a><span class="sd">        Empty lists are valid:</span>
+</span><span id="Message.check_value-256"><a href="#Message.check_value-256"><span class="linenos">256</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([])</span>
+</span><span id="Message.check_value-257"><a href="#Message.check_value-257"><span class="linenos">257</span></a><span class="sd">        True</span>
+</span><span id="Message.check_value-258"><a href="#Message.check_value-258"><span class="linenos">258</span></a>
+</span><span id="Message.check_value-259"><a href="#Message.check_value-259"><span class="linenos">259</span></a><span class="sd">        Lists with invalid elements are not valid:</span>
+</span><span id="Message.check_value-260"><a href="#Message.check_value-260"><span class="linenos">260</span></a><span class="sd">        &gt;&gt;&gt; Message.check_value([1j])</span>
+</span><span id="Message.check_value-261"><a href="#Message.check_value-261"><span class="linenos">261</span></a><span class="sd">        False</span>
+</span><span id="Message.check_value-262"><a href="#Message.check_value-262"><span class="linenos">262</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message.check_value-263"><a href="#Message.check_value-263"><span class="linenos">263</span></a>        <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message.check_value-264"><a href="#Message.check_value-264"><span class="linenos">264</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message.check_value-265"><a href="#Message.check_value-265"><span class="linenos">265</span></a>        <span class="k">elif</span> <span class="p">(</span>
+</span><span id="Message.check_value-266"><a href="#Message.check_value-266"><span class="linenos">266</span></a>            <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="Message.check_value-267"><a href="#Message.check_value-267"><span class="linenos">267</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
+</span><span id="Message.check_value-268"><a href="#Message.check_value-268"><span class="linenos">268</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
+</span><span id="Message.check_value-269"><a href="#Message.check_value-269"><span class="linenos">269</span></a>            <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="Message.check_value-270"><a href="#Message.check_value-270"><span class="linenos">270</span></a>        <span class="p">):</span>
+</span><span id="Message.check_value-271"><a href="#Message.check_value-271"><span class="linenos">271</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message.check_value-272"><a href="#Message.check_value-272"><span class="linenos">272</span></a>        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+</span><span id="Message.check_value-273"><a href="#Message.check_value-273"><span class="linenos">273</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="Message.check_value-274"><a href="#Message.check_value-274"><span class="linenos">274</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="Message.check_value-275"><a href="#Message.check_value-275"><span class="linenos">275</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message.check_value-276"><a href="#Message.check_value-276"><span class="linenos">276</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">Message</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="Message.check_value-277"><a href="#Message.check_value-277"><span class="linenos">277</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message.check_value-278"><a href="#Message.check_value-278"><span class="linenos">278</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message.check_value-279"><a href="#Message.check_value-279"><span class="linenos">279</span></a>        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="Message.check_value-280"><a href="#Message.check_value-280"><span class="linenos">280</span></a>            <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="Message.check_value-281"><a href="#Message.check_value-281"><span class="linenos">281</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">Message</span><span class="o">.</span><span class="n">check_value</span><span class="p">(</span><span class="n">element</span><span class="p">):</span>
+</span><span id="Message.check_value-282"><a href="#Message.check_value-282"><span class="linenos">282</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="Message.check_value-283"><a href="#Message.check_value-283"><span class="linenos">283</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="Message.check_value-284"><a href="#Message.check_value-284"><span class="linenos">284</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Check recursively if a given value is valid.</p>
+
+<p>None, strings, integers, floats and Booleans are valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="s1">&#39;Spam&#39;</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="mf">42.42</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Other basic types are not valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;bytes&#39;</span><span class="p">)</span>
+<span class="go">False</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">(</span><span class="mi">1</span><span class="n">j</span><span class="p">)</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>Dictionaries with string keys and recursively valid values are valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">({</span><span class="s1">&#39;str value&#39;</span><span class="p">:</span> <span class="s1">&#39;Spam&#39;</span><span class="p">,</span> <span class="s1">&#39;int value&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span>
+<span class="gp">... </span>                     <span class="s1">&#39;float value&#39;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">,</span> <span class="s1">&#39;bool value&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">})</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Empty dictionaries are valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">({})</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Dictionaries with other keys are not valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">({</span><span class="mi">42</span><span class="p">:</span> <span class="s1">&#39;int key&#39;</span><span class="p">})</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>Dictionaries with invalid values are not valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">({</span><span class="s1">&#39;complex value&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="n">j</span><span class="p">})</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>Lists with valid elements are valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">([</span><span class="s1">&#39;Spam&#39;</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="mf">42.42</span><span class="p">,</span> <span class="kc">False</span><span class="p">])</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Empty lists are valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">([])</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Lists with invalid elements are not valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n"><a href="#Message.check_value">Message.check_value</a></span><span class="p">([</span><span class="mi">1</span><span class="n">j</span><span class="p">])</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="Message.update" class="classattr">
+                                        <input id="Message.update-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">update</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="o">*</span><span class="n">args</span>, </span><span class="param"><span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Message.update-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Message.update"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Message.update-311"><a href="#Message.update-311"><span class="linenos">311</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Message.update-312"><a href="#Message.update-312"><span class="linenos">312</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override update to use validity checks.</span>
+</span><span id="Message.update-313"><a href="#Message.update-313"><span class="linenos">313</span></a>
+</span><span id="Message.update-314"><a href="#Message.update-314"><span class="linenos">314</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message.update-315"><a href="#Message.update-315"><span class="linenos">315</span></a><span class="sd">        &gt;&gt;&gt; m.update({&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})</span>
+</span><span id="Message.update-316"><a href="#Message.update-316"><span class="linenos">316</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message.update-317"><a href="#Message.update-317"><span class="linenos">317</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+</span><span id="Message.update-318"><a href="#Message.update-318"><span class="linenos">318</span></a><span class="sd">        &gt;&gt;&gt; m.update({42: &#39;int key&#39;})</span>
+</span><span id="Message.update-319"><a href="#Message.update-319"><span class="linenos">319</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message.update-320"><a href="#Message.update-320"><span class="linenos">320</span></a><span class="sd">          ...</span>
+</span><span id="Message.update-321"><a href="#Message.update-321"><span class="linenos">321</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message.update-322"><a href="#Message.update-322"><span class="linenos">322</span></a><span class="sd">        &gt;&gt;&gt; m.update({&#39;complex value&#39;: 1j})</span>
+</span><span id="Message.update-323"><a href="#Message.update-323"><span class="linenos">323</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message.update-324"><a href="#Message.update-324"><span class="linenos">324</span></a><span class="sd">          ...</span>
+</span><span id="Message.update-325"><a href="#Message.update-325"><span class="linenos">325</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message.update-326"><a href="#Message.update-326"><span class="linenos">326</span></a>
+</span><span id="Message.update-327"><a href="#Message.update-327"><span class="linenos">327</span></a><span class="sd">        This is also used in __init__:</span>
+</span><span id="Message.update-328"><a href="#Message.update-328"><span class="linenos">328</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="Message.update-329"><a href="#Message.update-329"><span class="linenos">329</span></a><span class="sd">        &gt;&gt;&gt; print(m)</span>
+</span><span id="Message.update-330"><a href="#Message.update-330"><span class="linenos">330</span></a><span class="sd">        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="Message.update-331"><a href="#Message.update-331"><span class="linenos">331</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {42: &#39;int key&#39;})</span>
+</span><span id="Message.update-332"><a href="#Message.update-332"><span class="linenos">332</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message.update-333"><a href="#Message.update-333"><span class="linenos">333</span></a><span class="sd">          ...</span>
+</span><span id="Message.update-334"><a href="#Message.update-334"><span class="linenos">334</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message.update-335"><a href="#Message.update-335"><span class="linenos">335</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;complex value&#39;: 1j})</span>
+</span><span id="Message.update-336"><a href="#Message.update-336"><span class="linenos">336</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message.update-337"><a href="#Message.update-337"><span class="linenos">337</span></a><span class="sd">          ...</span>
+</span><span id="Message.update-338"><a href="#Message.update-338"><span class="linenos">338</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message.update-339"><a href="#Message.update-339"><span class="linenos">339</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message.update-340"><a href="#Message.update-340"><span class="linenos">340</span></a>        <span class="k">if</span> <span class="n">args</span><span class="p">:</span>
+</span><span id="Message.update-341"><a href="#Message.update-341"><span class="linenos">341</span></a>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+</span><span id="Message.update-342"><a href="#Message.update-342"><span class="linenos">342</span></a>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;update expected at most 1 argument, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="Message.update-343"><a href="#Message.update-343"><span class="linenos">343</span></a>            <span class="n">other</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</span><span id="Message.update-344"><a href="#Message.update-344"><span class="linenos">344</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">other</span><span class="p">:</span>
+</span><span id="Message.update-345"><a href="#Message.update-345"><span class="linenos">345</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">other</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="Message.update-346"><a href="#Message.update-346"><span class="linenos">346</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
+</span><span id="Message.update-347"><a href="#Message.update-347"><span class="linenos">347</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Override update to use validity checks.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value 1&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;value 2&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="mi">42</span><span class="p">:</span> <span class="s1">&#39;int key&#39;</span><span class="p">})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;42&#39; is not a valid key in Message (not a string).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s1">&#39;complex value&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="n">j</span><span class="p">})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;1j&#39; is not a valid value in Message.</span>
+</code></pre>
+</div>
+
+<p>This is also used in __init__:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="mi">42</span><span class="p">:</span> <span class="s1">&#39;int key&#39;</span><span class="p">})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;42&#39; is not a valid key in Message (not a string).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;complex value&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="n">j</span><span class="p">})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;1j&#39; is not a valid value in Message.</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="Message.setdefault" class="classattr">
+                                        <input id="Message.setdefault-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">setdefault</span><span class="signature pdoc-code multiline">(<span class="param">  <span class="bp">self</span>,</span><span class="param">        <span class="n">key</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">      <span class="n">value</span><span class="p">:</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]</span>:</span></span>
+
+                <label class="view-source-button" for="Message.setdefault-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Message.setdefault"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Message.setdefault-349"><a href="#Message.setdefault-349"><span class="linenos">349</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MessageValue</span><span class="p">:</span>
+</span><span id="Message.setdefault-350"><a href="#Message.setdefault-350"><span class="linenos">350</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override setdefault to use validity checks.</span>
+</span><span id="Message.setdefault-351"><a href="#Message.setdefault-351"><span class="linenos">351</span></a>
+</span><span id="Message.setdefault-352"><a href="#Message.setdefault-352"><span class="linenos">352</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)</span>
+</span><span id="Message.setdefault-353"><a href="#Message.setdefault-353"><span class="linenos">353</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 1&#39;)</span>
+</span><span id="Message.setdefault-354"><a href="#Message.setdefault-354"><span class="linenos">354</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="Message.setdefault-355"><a href="#Message.setdefault-355"><span class="linenos">355</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 2&#39;)</span>
+</span><span id="Message.setdefault-356"><a href="#Message.setdefault-356"><span class="linenos">356</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="Message.setdefault-357"><a href="#Message.setdefault-357"><span class="linenos">357</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(42, &#39;int key&#39;)</span>
+</span><span id="Message.setdefault-358"><a href="#Message.setdefault-358"><span class="linenos">358</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message.setdefault-359"><a href="#Message.setdefault-359"><span class="linenos">359</span></a><span class="sd">          ...</span>
+</span><span id="Message.setdefault-360"><a href="#Message.setdefault-360"><span class="linenos">360</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in Message (not a string).</span>
+</span><span id="Message.setdefault-361"><a href="#Message.setdefault-361"><span class="linenos">361</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;complex value&#39;, 1j)</span>
+</span><span id="Message.setdefault-362"><a href="#Message.setdefault-362"><span class="linenos">362</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="Message.setdefault-363"><a href="#Message.setdefault-363"><span class="linenos">363</span></a><span class="sd">          ...</span>
+</span><span id="Message.setdefault-364"><a href="#Message.setdefault-364"><span class="linenos">364</span></a><span class="sd">        TypeError: &#39;1j&#39; is not a valid value in Message.</span>
+</span><span id="Message.setdefault-365"><a href="#Message.setdefault-365"><span class="linenos">365</span></a>
+</span><span id="Message.setdefault-366"><a href="#Message.setdefault-366"><span class="linenos">366</span></a><span class="sd">        But __setitem__ is not called if the key is already present:</span>
+</span><span id="Message.setdefault-367"><a href="#Message.setdefault-367"><span class="linenos">367</span></a><span class="sd">        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, 1j)</span>
+</span><span id="Message.setdefault-368"><a href="#Message.setdefault-368"><span class="linenos">368</span></a><span class="sd">        &#39;value 1&#39;</span>
+</span><span id="Message.setdefault-369"><a href="#Message.setdefault-369"><span class="linenos">369</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="Message.setdefault-370"><a href="#Message.setdefault-370"><span class="linenos">370</span></a>        <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="Message.setdefault-371"><a href="#Message.setdefault-371"><span class="linenos">371</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="Message.setdefault-372"><a href="#Message.setdefault-372"><span class="linenos">372</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Override setdefault to use validity checks.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example sender&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key&#39;</span><span class="p">,</span> <span class="s1">&#39;value 1&#39;</span><span class="p">)</span>
+<span class="go">&#39;value 1&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key&#39;</span><span class="p">,</span> <span class="s1">&#39;value 2&#39;</span><span class="p">)</span>
+<span class="go">&#39;value 1&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="s1">&#39;int key&#39;</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;42&#39; is not a valid key in Message (not a string).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;complex value&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="n">j</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;1j&#39; is not a valid value in Message.</span>
+</code></pre>
+</div>
+
+<p>But __setitem__ is not called if the key is already present:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="n">j</span><span class="p">)</span>
+<span class="go">&#39;value 1&#39;</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                </section>
+                <section id="MessageTemplate">
+                            <input id="MessageTemplate-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">MessageTemplate</span><wbr>(<span class="base">typing.Dict[str, bool | typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]]</span>):
+
+                <label class="view-source-button" for="MessageTemplate-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageTemplate"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageTemplate-375"><a href="#MessageTemplate-375"><span class="linenos">375</span></a><span class="k">class</span><span class="w"> </span><span class="nc">MessageTemplate</span><span class="p">(</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">JSONSchema</span><span class="p">]):</span>
+</span><span id="MessageTemplate-376"><a href="#MessageTemplate-376"><span class="linenos">376</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define a message template.</span>
+</span><span id="MessageTemplate-377"><a href="#MessageTemplate-377"><span class="linenos">377</span></a>
+</span><span id="MessageTemplate-378"><a href="#MessageTemplate-378"><span class="linenos">378</span></a><span class="sd">    A message template is a mapping from string keys to JSON schemas as</span>
+</span><span id="MessageTemplate-379"><a href="#MessageTemplate-379"><span class="linenos">379</span></a><span class="sd">    values:</span>
+</span><span id="MessageTemplate-380"><a href="#MessageTemplate-380"><span class="linenos">380</span></a><span class="sd">    &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate-381"><a href="#MessageTemplate-381"><span class="linenos">381</span></a><span class="sd">    ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;}})</span>
+</span><span id="MessageTemplate-382"><a href="#MessageTemplate-382"><span class="linenos">382</span></a><span class="sd">    &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-383"><a href="#MessageTemplate-383"><span class="linenos">383</span></a><span class="sd">    ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-384"><a href="#MessageTemplate-384"><span class="linenos">384</span></a><span class="sd">    ...                              &#39;key 2&#39;: True}}</span>
+</span><span id="MessageTemplate-385"><a href="#MessageTemplate-385"><span class="linenos">385</span></a>
+</span><span id="MessageTemplate-386"><a href="#MessageTemplate-386"><span class="linenos">386</span></a><span class="sd">    A message template matches a message if all keys of the template are</span>
+</span><span id="MessageTemplate-387"><a href="#MessageTemplate-387"><span class="linenos">387</span></a><span class="sd">    contained in the message and the values in the message validate against</span>
+</span><span id="MessageTemplate-388"><a href="#MessageTemplate-388"><span class="linenos">388</span></a><span class="sd">    the respective schemas:</span>
+</span><span id="MessageTemplate-389"><a href="#MessageTemplate-389"><span class="linenos">389</span></a><span class="sd">    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate-390"><a href="#MessageTemplate-390"><span class="linenos">390</span></a><span class="sd">    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate-391"><a href="#MessageTemplate-391"><span class="linenos">391</span></a><span class="sd">    ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42, &#39;key 2&#39;: None}}))</span>
+</span><span id="MessageTemplate-392"><a href="#MessageTemplate-392"><span class="linenos">392</span></a><span class="sd">    True</span>
+</span><span id="MessageTemplate-393"><a href="#MessageTemplate-393"><span class="linenos">393</span></a>
+</span><span id="MessageTemplate-394"><a href="#MessageTemplate-394"><span class="linenos">394</span></a><span class="sd">    An empty mapping therefore matches all messages:</span>
+</span><span id="MessageTemplate-395"><a href="#MessageTemplate-395"><span class="linenos">395</span></a><span class="sd">    &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate-396"><a href="#MessageTemplate-396"><span class="linenos">396</span></a><span class="sd">    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;arbitrary&#39;: &#39;content&#39;}))</span>
+</span><span id="MessageTemplate-397"><a href="#MessageTemplate-397"><span class="linenos">397</span></a><span class="sd">    True</span>
+</span><span id="MessageTemplate-398"><a href="#MessageTemplate-398"><span class="linenos">398</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-399"><a href="#MessageTemplate-399"><span class="linenos">399</span></a>
+</span><span id="MessageTemplate-400"><a href="#MessageTemplate-400"><span class="linenos">400</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">init</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">JSONSchema</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate-401"><a href="#MessageTemplate-401"><span class="linenos">401</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise message.</span>
+</span><span id="MessageTemplate-402"><a href="#MessageTemplate-402"><span class="linenos">402</span></a>
+</span><span id="MessageTemplate-403"><a href="#MessageTemplate-403"><span class="linenos">403</span></a><span class="sd">        Template is initialised empty or with given key-value pairs:</span>
+</span><span id="MessageTemplate-404"><a href="#MessageTemplate-404"><span class="linenos">404</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate-405"><a href="#MessageTemplate-405"><span class="linenos">405</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="MessageTemplate-406"><a href="#MessageTemplate-406"><span class="linenos">406</span></a><span class="sd">        {}</span>
+</span><span id="MessageTemplate-407"><a href="#MessageTemplate-407"><span class="linenos">407</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})</span>
+</span><span id="MessageTemplate-408"><a href="#MessageTemplate-408"><span class="linenos">408</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="MessageTemplate-409"><a href="#MessageTemplate-409"><span class="linenos">409</span></a><span class="sd">        {&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</span><span id="MessageTemplate-410"><a href="#MessageTemplate-410"><span class="linenos">410</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-411"><a href="#MessageTemplate-411"><span class="linenos">411</span></a>        <span class="k">if</span> <span class="n">init</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate-412"><a href="#MessageTemplate-412"><span class="linenos">412</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">init</span><span class="p">)</span>
+</span><span id="MessageTemplate-413"><a href="#MessageTemplate-413"><span class="linenos">413</span></a>
+</span><span id="MessageTemplate-414"><a href="#MessageTemplate-414"><span class="linenos">414</span></a>    <span class="nd">@staticmethod</span>
+</span><span id="MessageTemplate-415"><a href="#MessageTemplate-415"><span class="linenos">415</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">from_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;MessageTemplate&quot;</span><span class="p">:</span>
+</span><span id="MessageTemplate-416"><a href="#MessageTemplate-416"><span class="linenos">416</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Create template from message.</span>
+</span><span id="MessageTemplate-417"><a href="#MessageTemplate-417"><span class="linenos">417</span></a>
+</span><span id="MessageTemplate-418"><a href="#MessageTemplate-418"><span class="linenos">418</span></a><span class="sd">        Template witch constant schemas is created from message:</span>
+</span><span id="MessageTemplate-419"><a href="#MessageTemplate-419"><span class="linenos">419</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="MessageTemplate-420"><a href="#MessageTemplate-420"><span class="linenos">420</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="MessageTemplate-421"><a href="#MessageTemplate-421"><span class="linenos">421</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="MessageTemplate-422"><a href="#MessageTemplate-422"><span class="linenos">422</span></a><span class="sd">        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</span><span id="MessageTemplate-423"><a href="#MessageTemplate-423"><span class="linenos">423</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},</span>
+</span><span id="MessageTemplate-424"><a href="#MessageTemplate-424"><span class="linenos">424</span></a><span class="sd">        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})</span>
+</span><span id="MessageTemplate-425"><a href="#MessageTemplate-425"><span class="linenos">425</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="MessageTemplate-426"><a href="#MessageTemplate-426"><span class="linenos">426</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-427"><a href="#MessageTemplate-427"><span class="linenos">427</span></a><span class="sd">        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},</span>
+</span><span id="MessageTemplate-428"><a href="#MessageTemplate-428"><span class="linenos">428</span></a><span class="sd">         &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-429"><a href="#MessageTemplate-429"><span class="linenos">429</span></a><span class="sd">                  &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="MessageTemplate-430"><a href="#MessageTemplate-430"><span class="linenos">430</span></a><span class="sd">                                 &#39;float&#39;: {&#39;const&#39;: 42.42}}},</span>
+</span><span id="MessageTemplate-431"><a href="#MessageTemplate-431"><span class="linenos">431</span></a><span class="sd">         &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+</span><span id="MessageTemplate-432"><a href="#MessageTemplate-432"><span class="linenos">432</span></a><span class="sd">                  &#39;items&#39;: [{&#39;const&#39;: None},</span>
+</span><span id="MessageTemplate-433"><a href="#MessageTemplate-433"><span class="linenos">433</span></a><span class="sd">                            {&#39;const&#39;: True},</span>
+</span><span id="MessageTemplate-434"><a href="#MessageTemplate-434"><span class="linenos">434</span></a><span class="sd">                            {&#39;const&#39;: &#39;string&#39;}]}}</span>
+</span><span id="MessageTemplate-435"><a href="#MessageTemplate-435"><span class="linenos">435</span></a>
+</span><span id="MessageTemplate-436"><a href="#MessageTemplate-436"><span class="linenos">436</span></a><span class="sd">        This is especially useful for clients that send certain fully</span>
+</span><span id="MessageTemplate-437"><a href="#MessageTemplate-437"><span class="linenos">437</span></a><span class="sd">        predefined messages, where the message is given in the configuration</span>
+</span><span id="MessageTemplate-438"><a href="#MessageTemplate-438"><span class="linenos">438</span></a><span class="sd">        and the template for the registration can be constructed by this</span>
+</span><span id="MessageTemplate-439"><a href="#MessageTemplate-439"><span class="linenos">439</span></a><span class="sd">        method.</span>
+</span><span id="MessageTemplate-440"><a href="#MessageTemplate-440"><span class="linenos">440</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-441"><a href="#MessageTemplate-441"><span class="linenos">441</span></a>
+</span><span id="MessageTemplate-442"><a href="#MessageTemplate-442"><span class="linenos">442</span></a>        <span class="k">def</span><span class="w"> </span><span class="nf">schema_from_value</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">JSONSchema</span><span class="p">:</span>
+</span><span id="MessageTemplate-443"><a href="#MessageTemplate-443"><span class="linenos">443</span></a>            <span class="n">schema</span><span class="p">:</span> <span class="n">JSONSchema</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="MessageTemplate-444"><a href="#MessageTemplate-444"><span class="linenos">444</span></a>            <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate-445"><a href="#MessageTemplate-445"><span class="linenos">445</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span>
+</span><span id="MessageTemplate-446"><a href="#MessageTemplate-446"><span class="linenos">446</span></a>            <span class="k">elif</span> <span class="p">(</span>
+</span><span id="MessageTemplate-447"><a href="#MessageTemplate-447"><span class="linenos">447</span></a>                <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="MessageTemplate-448"><a href="#MessageTemplate-448"><span class="linenos">448</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
+</span><span id="MessageTemplate-449"><a href="#MessageTemplate-449"><span class="linenos">449</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
+</span><span id="MessageTemplate-450"><a href="#MessageTemplate-450"><span class="linenos">450</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="MessageTemplate-451"><a href="#MessageTemplate-451"><span class="linenos">451</span></a>            <span class="p">):</span>
+</span><span id="MessageTemplate-452"><a href="#MessageTemplate-452"><span class="linenos">452</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">value</span><span class="p">}</span>
+</span><span id="MessageTemplate-453"><a href="#MessageTemplate-453"><span class="linenos">453</span></a>            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+</span><span id="MessageTemplate-454"><a href="#MessageTemplate-454"><span class="linenos">454</span></a>                <span class="n">properties</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="MessageTemplate-455"><a href="#MessageTemplate-455"><span class="linenos">455</span></a>                <span class="k">for</span> <span class="n">inner_key</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="MessageTemplate-456"><a href="#MessageTemplate-456"><span class="linenos">456</span></a>                    <span class="n">inner_value</span><span class="p">:</span> <span class="n">Message</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="n">inner_key</span><span class="p">]</span>
+</span><span id="MessageTemplate-457"><a href="#MessageTemplate-457"><span class="linenos">457</span></a>                    <span class="n">properties</span><span class="p">[</span><span class="n">inner_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">schema_from_value</span><span class="p">(</span><span class="n">inner_value</span><span class="p">)</span>
+</span><span id="MessageTemplate-458"><a href="#MessageTemplate-458"><span class="linenos">458</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">,</span> <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="n">properties</span><span class="p">}</span>
+</span><span id="MessageTemplate-459"><a href="#MessageTemplate-459"><span class="linenos">459</span></a>            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="MessageTemplate-460"><a href="#MessageTemplate-460"><span class="linenos">460</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="MessageTemplate-461"><a href="#MessageTemplate-461"><span class="linenos">461</span></a>                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="MessageTemplate-462"><a href="#MessageTemplate-462"><span class="linenos">462</span></a>                    <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">schema_from_value</span><span class="p">(</span><span class="n">element</span><span class="p">)</span> <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">value</span><span class="p">],</span>
+</span><span id="MessageTemplate-463"><a href="#MessageTemplate-463"><span class="linenos">463</span></a>                <span class="p">}</span>
+</span><span id="MessageTemplate-464"><a href="#MessageTemplate-464"><span class="linenos">464</span></a>            <span class="k">return</span> <span class="n">schema</span>
+</span><span id="MessageTemplate-465"><a href="#MessageTemplate-465"><span class="linenos">465</span></a>
+</span><span id="MessageTemplate-466"><a href="#MessageTemplate-466"><span class="linenos">466</span></a>        <span class="n">template</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+</span><span id="MessageTemplate-467"><a href="#MessageTemplate-467"><span class="linenos">467</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="MessageTemplate-468"><a href="#MessageTemplate-468"><span class="linenos">468</span></a>            <span class="n">template</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">schema_from_value</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
+</span><span id="MessageTemplate-469"><a href="#MessageTemplate-469"><span class="linenos">469</span></a>        <span class="k">return</span> <span class="n">template</span>
+</span><span id="MessageTemplate-470"><a href="#MessageTemplate-470"><span class="linenos">470</span></a>
+</span><span id="MessageTemplate-471"><a href="#MessageTemplate-471"><span class="linenos">471</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">JSONSchema</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate-472"><a href="#MessageTemplate-472"><span class="linenos">472</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check key and value before putting pair into dict.</span>
+</span><span id="MessageTemplate-473"><a href="#MessageTemplate-473"><span class="linenos">473</span></a>
+</span><span id="MessageTemplate-474"><a href="#MessageTemplate-474"><span class="linenos">474</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate-475"><a href="#MessageTemplate-475"><span class="linenos">475</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key 1&#39;] = {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="MessageTemplate-476"><a href="#MessageTemplate-476"><span class="linenos">476</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key 2&#39;] = {&#39;type&#39;: &#39;string&#39;}</span>
+</span><span id="MessageTemplate-477"><a href="#MessageTemplate-477"><span class="linenos">477</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-478"><a href="#MessageTemplate-478"><span class="linenos">478</span></a><span class="sd">        ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-479"><a href="#MessageTemplate-479"><span class="linenos">479</span></a><span class="sd">        ...                              &#39;key 2&#39;: True}}</span>
+</span><span id="MessageTemplate-480"><a href="#MessageTemplate-480"><span class="linenos">480</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-481"><a href="#MessageTemplate-481"><span class="linenos">481</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate-482"><a href="#MessageTemplate-482"><span class="linenos">482</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-483"><a href="#MessageTemplate-483"><span class="linenos">483</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-484"><a href="#MessageTemplate-484"><span class="linenos">484</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="MessageTemplate-485"><a href="#MessageTemplate-485"><span class="linenos">485</span></a><span class="sd">        &gt;&gt;&gt; t[42] = {&#39;const&#39;: &#39;int key&#39;}</span>
+</span><span id="MessageTemplate-486"><a href="#MessageTemplate-486"><span class="linenos">486</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-487"><a href="#MessageTemplate-487"><span class="linenos">487</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-488"><a href="#MessageTemplate-488"><span class="linenos">488</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate-489"><a href="#MessageTemplate-489"><span class="linenos">489</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key&#39;] = &#39;schema&#39;  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-490"><a href="#MessageTemplate-490"><span class="linenos">490</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-491"><a href="#MessageTemplate-491"><span class="linenos">491</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-492"><a href="#MessageTemplate-492"><span class="linenos">492</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate-493"><a href="#MessageTemplate-493"><span class="linenos">493</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate-494"><a href="#MessageTemplate-494"><span class="linenos">494</span></a><span class="sd">        &gt;&gt;&gt; t[&#39;key&#39;] = True</span>
+</span><span id="MessageTemplate-495"><a href="#MessageTemplate-495"><span class="linenos">495</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-496"><a href="#MessageTemplate-496"><span class="linenos">496</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
+</span><span id="MessageTemplate-497"><a href="#MessageTemplate-497"><span class="linenos">497</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span>
+</span><span id="MessageTemplate-498"><a href="#MessageTemplate-498"><span class="linenos">498</span></a>                <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2">&#39; is not a valid key in MessageTemplate (not a string).&quot;</span>
+</span><span id="MessageTemplate-499"><a href="#MessageTemplate-499"><span class="linenos">499</span></a>            <span class="p">)</span>
+</span><span id="MessageTemplate-500"><a href="#MessageTemplate-500"><span class="linenos">500</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">register_schema</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
+</span><span id="MessageTemplate-501"><a href="#MessageTemplate-501"><span class="linenos">501</span></a>            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span>
+</span><span id="MessageTemplate-502"><a href="#MessageTemplate-502"><span class="linenos">502</span></a>                <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">&#39; is not a valid value in&quot;</span>
+</span><span id="MessageTemplate-503"><a href="#MessageTemplate-503"><span class="linenos">503</span></a>                <span class="s2">&quot; MessageTemplate (not a valid JSON schema).&quot;</span>
+</span><span id="MessageTemplate-504"><a href="#MessageTemplate-504"><span class="linenos">504</span></a>            <span class="p">)</span>
+</span><span id="MessageTemplate-505"><a href="#MessageTemplate-505"><span class="linenos">505</span></a>        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__setitem__</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+</span><span id="MessageTemplate-506"><a href="#MessageTemplate-506"><span class="linenos">506</span></a>
+</span><span id="MessageTemplate-507"><a href="#MessageTemplate-507"><span class="linenos">507</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate-508"><a href="#MessageTemplate-508"><span class="linenos">508</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override update to use validity checks.</span>
+</span><span id="MessageTemplate-509"><a href="#MessageTemplate-509"><span class="linenos">509</span></a>
+</span><span id="MessageTemplate-510"><a href="#MessageTemplate-510"><span class="linenos">510</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate-511"><a href="#MessageTemplate-511"><span class="linenos">511</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate-512"><a href="#MessageTemplate-512"><span class="linenos">512</span></a><span class="sd">        ...           &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate-513"><a href="#MessageTemplate-513"><span class="linenos">513</span></a><span class="sd">        ...           &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-514"><a href="#MessageTemplate-514"><span class="linenos">514</span></a><span class="sd">        ...                     &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-515"><a href="#MessageTemplate-515"><span class="linenos">515</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True}}})</span>
+</span><span id="MessageTemplate-516"><a href="#MessageTemplate-516"><span class="linenos">516</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-517"><a href="#MessageTemplate-517"><span class="linenos">517</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate-518"><a href="#MessageTemplate-518"><span class="linenos">518</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-519"><a href="#MessageTemplate-519"><span class="linenos">519</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-520"><a href="#MessageTemplate-520"><span class="linenos">520</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="MessageTemplate-521"><a href="#MessageTemplate-521"><span class="linenos">521</span></a><span class="sd">        &gt;&gt;&gt; t.update({42: {&#39;const&#39;: &#39;int key&#39;}})</span>
+</span><span id="MessageTemplate-522"><a href="#MessageTemplate-522"><span class="linenos">522</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-523"><a href="#MessageTemplate-523"><span class="linenos">523</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-524"><a href="#MessageTemplate-524"><span class="linenos">524</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate-525"><a href="#MessageTemplate-525"><span class="linenos">525</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key&#39;: &#39;schema&#39;})  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-526"><a href="#MessageTemplate-526"><span class="linenos">526</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-527"><a href="#MessageTemplate-527"><span class="linenos">527</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-528"><a href="#MessageTemplate-528"><span class="linenos">528</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate-529"><a href="#MessageTemplate-529"><span class="linenos">529</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate-530"><a href="#MessageTemplate-530"><span class="linenos">530</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key&#39;: True})</span>
+</span><span id="MessageTemplate-531"><a href="#MessageTemplate-531"><span class="linenos">531</span></a>
+</span><span id="MessageTemplate-532"><a href="#MessageTemplate-532"><span class="linenos">532</span></a><span class="sd">        This is also used in __init__:</span>
+</span><span id="MessageTemplate-533"><a href="#MessageTemplate-533"><span class="linenos">533</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate-534"><a href="#MessageTemplate-534"><span class="linenos">534</span></a><span class="sd">        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate-535"><a href="#MessageTemplate-535"><span class="linenos">535</span></a><span class="sd">        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-536"><a href="#MessageTemplate-536"><span class="linenos">536</span></a><span class="sd">        ...                                &#39;properties&#39;: {</span>
+</span><span id="MessageTemplate-537"><a href="#MessageTemplate-537"><span class="linenos">537</span></a><span class="sd">        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-538"><a href="#MessageTemplate-538"><span class="linenos">538</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True}}})</span>
+</span><span id="MessageTemplate-539"><a href="#MessageTemplate-539"><span class="linenos">539</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-540"><a href="#MessageTemplate-540"><span class="linenos">540</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate-541"><a href="#MessageTemplate-541"><span class="linenos">541</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-542"><a href="#MessageTemplate-542"><span class="linenos">542</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-543"><a href="#MessageTemplate-543"><span class="linenos">543</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="MessageTemplate-544"><a href="#MessageTemplate-544"><span class="linenos">544</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({42: {&#39;const&#39;: &#39;int key&#39;}})</span>
+</span><span id="MessageTemplate-545"><a href="#MessageTemplate-545"><span class="linenos">545</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-546"><a href="#MessageTemplate-546"><span class="linenos">546</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-547"><a href="#MessageTemplate-547"><span class="linenos">547</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate-548"><a href="#MessageTemplate-548"><span class="linenos">548</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: &#39;schema&#39;})</span>
+</span><span id="MessageTemplate-549"><a href="#MessageTemplate-549"><span class="linenos">549</span></a><span class="sd">        ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-550"><a href="#MessageTemplate-550"><span class="linenos">550</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-551"><a href="#MessageTemplate-551"><span class="linenos">551</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-552"><a href="#MessageTemplate-552"><span class="linenos">552</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate-553"><a href="#MessageTemplate-553"><span class="linenos">553</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate-554"><a href="#MessageTemplate-554"><span class="linenos">554</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: True})</span>
+</span><span id="MessageTemplate-555"><a href="#MessageTemplate-555"><span class="linenos">555</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-556"><a href="#MessageTemplate-556"><span class="linenos">556</span></a>        <span class="k">if</span> <span class="n">args</span><span class="p">:</span>
+</span><span id="MessageTemplate-557"><a href="#MessageTemplate-557"><span class="linenos">557</span></a>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+</span><span id="MessageTemplate-558"><a href="#MessageTemplate-558"><span class="linenos">558</span></a>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;update expected at most 1 argument, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="MessageTemplate-559"><a href="#MessageTemplate-559"><span class="linenos">559</span></a>            <span class="n">other</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</span><span id="MessageTemplate-560"><a href="#MessageTemplate-560"><span class="linenos">560</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">other</span><span class="p">:</span>
+</span><span id="MessageTemplate-561"><a href="#MessageTemplate-561"><span class="linenos">561</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">other</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="MessageTemplate-562"><a href="#MessageTemplate-562"><span class="linenos">562</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
+</span><span id="MessageTemplate-563"><a href="#MessageTemplate-563"><span class="linenos">563</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="MessageTemplate-564"><a href="#MessageTemplate-564"><span class="linenos">564</span></a>
+</span><span id="MessageTemplate-565"><a href="#MessageTemplate-565"><span class="linenos">565</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">JSONSchema</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">JSONSchema</span><span class="p">:</span>
+</span><span id="MessageTemplate-566"><a href="#MessageTemplate-566"><span class="linenos">566</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override setdefault to use validity checks.</span>
+</span><span id="MessageTemplate-567"><a href="#MessageTemplate-567"><span class="linenos">567</span></a>
+</span><span id="MessageTemplate-568"><a href="#MessageTemplate-568"><span class="linenos">568</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate-569"><a href="#MessageTemplate-569"><span class="linenos">569</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, {&#39;const&#39;: &#39;value&#39;})</span>
+</span><span id="MessageTemplate-570"><a href="#MessageTemplate-570"><span class="linenos">570</span></a><span class="sd">        {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="MessageTemplate-571"><a href="#MessageTemplate-571"><span class="linenos">571</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 2&#39;, {&#39;type&#39;: &#39;string&#39;})</span>
+</span><span id="MessageTemplate-572"><a href="#MessageTemplate-572"><span class="linenos">572</span></a><span class="sd">        {&#39;type&#39;: &#39;string&#39;}</span>
+</span><span id="MessageTemplate-573"><a href="#MessageTemplate-573"><span class="linenos">573</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 3&#39;, {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-574"><a href="#MessageTemplate-574"><span class="linenos">574</span></a><span class="sd">        ...                        &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-575"><a href="#MessageTemplate-575"><span class="linenos">575</span></a><span class="sd">        ...                                       &#39;key 2&#39;: True}})</span>
+</span><span id="MessageTemplate-576"><a href="#MessageTemplate-576"><span class="linenos">576</span></a><span class="sd">        ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-577"><a href="#MessageTemplate-577"><span class="linenos">577</span></a><span class="sd">        {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-578"><a href="#MessageTemplate-578"><span class="linenos">578</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-579"><a href="#MessageTemplate-579"><span class="linenos">579</span></a><span class="sd">                                  &#39;key 2&#39;: True}}</span>
+</span><span id="MessageTemplate-580"><a href="#MessageTemplate-580"><span class="linenos">580</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(42, {&#39;const&#39;: &#39;int key&#39;})</span>
+</span><span id="MessageTemplate-581"><a href="#MessageTemplate-581"><span class="linenos">581</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-582"><a href="#MessageTemplate-582"><span class="linenos">582</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-583"><a href="#MessageTemplate-583"><span class="linenos">583</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate-584"><a href="#MessageTemplate-584"><span class="linenos">584</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key&#39;, &#39;schema&#39;)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate-585"><a href="#MessageTemplate-585"><span class="linenos">585</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate-586"><a href="#MessageTemplate-586"><span class="linenos">586</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate-587"><a href="#MessageTemplate-587"><span class="linenos">587</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate-588"><a href="#MessageTemplate-588"><span class="linenos">588</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate-589"><a href="#MessageTemplate-589"><span class="linenos">589</span></a>
+</span><span id="MessageTemplate-590"><a href="#MessageTemplate-590"><span class="linenos">590</span></a><span class="sd">        But __setitem__ is not called if the key is already present:</span>
+</span><span id="MessageTemplate-591"><a href="#MessageTemplate-591"><span class="linenos">591</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, &#39;schema&#39;)</span>
+</span><span id="MessageTemplate-592"><a href="#MessageTemplate-592"><span class="linenos">592</span></a><span class="sd">        {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="MessageTemplate-593"><a href="#MessageTemplate-593"><span class="linenos">593</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-594"><a href="#MessageTemplate-594"><span class="linenos">594</span></a>        <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="MessageTemplate-595"><a href="#MessageTemplate-595"><span class="linenos">595</span></a>            <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate-596"><a href="#MessageTemplate-596"><span class="linenos">596</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="MessageTemplate-597"><a href="#MessageTemplate-597"><span class="linenos">597</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="MessageTemplate-598"><a href="#MessageTemplate-598"><span class="linenos">598</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="MessageTemplate-599"><a href="#MessageTemplate-599"><span class="linenos">599</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="MessageTemplate-600"><a href="#MessageTemplate-600"><span class="linenos">600</span></a>
+</span><span id="MessageTemplate-601"><a href="#MessageTemplate-601"><span class="linenos">601</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="MessageTemplate-602"><a href="#MessageTemplate-602"><span class="linenos">602</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check message against this template.</span>
+</span><span id="MessageTemplate-603"><a href="#MessageTemplate-603"><span class="linenos">603</span></a>
+</span><span id="MessageTemplate-604"><a href="#MessageTemplate-604"><span class="linenos">604</span></a><span class="sd">        Constant values have to match exactly:</span>
+</span><span id="MessageTemplate-605"><a href="#MessageTemplate-605"><span class="linenos">605</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})</span>
+</span><span id="MessageTemplate-606"><a href="#MessageTemplate-606"><span class="linenos">606</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;}))</span>
+</span><span id="MessageTemplate-607"><a href="#MessageTemplate-607"><span class="linenos">607</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-608"><a href="#MessageTemplate-608"><span class="linenos">608</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;other value&#39;}))</span>
+</span><span id="MessageTemplate-609"><a href="#MessageTemplate-609"><span class="linenos">609</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate-610"><a href="#MessageTemplate-610"><span class="linenos">610</span></a>
+</span><span id="MessageTemplate-611"><a href="#MessageTemplate-611"><span class="linenos">611</span></a><span class="sd">        But for integers, floats with the same value are also valid:</span>
+</span><span id="MessageTemplate-612"><a href="#MessageTemplate-612"><span class="linenos">612</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: 42}})</span>
+</span><span id="MessageTemplate-613"><a href="#MessageTemplate-613"><span class="linenos">613</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="MessageTemplate-614"><a href="#MessageTemplate-614"><span class="linenos">614</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-615"><a href="#MessageTemplate-615"><span class="linenos">615</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))</span>
+</span><span id="MessageTemplate-616"><a href="#MessageTemplate-616"><span class="linenos">616</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-617"><a href="#MessageTemplate-617"><span class="linenos">617</span></a>
+</span><span id="MessageTemplate-618"><a href="#MessageTemplate-618"><span class="linenos">618</span></a><span class="sd">        Type integer is valid for floats with zero fractional part, but</span>
+</span><span id="MessageTemplate-619"><a href="#MessageTemplate-619"><span class="linenos">619</span></a><span class="sd">        not by floats with non-zero fractional part:</span>
+</span><span id="MessageTemplate-620"><a href="#MessageTemplate-620"><span class="linenos">620</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;integer&#39;}})</span>
+</span><span id="MessageTemplate-621"><a href="#MessageTemplate-621"><span class="linenos">621</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="MessageTemplate-622"><a href="#MessageTemplate-622"><span class="linenos">622</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-623"><a href="#MessageTemplate-623"><span class="linenos">623</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))</span>
+</span><span id="MessageTemplate-624"><a href="#MessageTemplate-624"><span class="linenos">624</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-625"><a href="#MessageTemplate-625"><span class="linenos">625</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))</span>
+</span><span id="MessageTemplate-626"><a href="#MessageTemplate-626"><span class="linenos">626</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate-627"><a href="#MessageTemplate-627"><span class="linenos">627</span></a>
+</span><span id="MessageTemplate-628"><a href="#MessageTemplate-628"><span class="linenos">628</span></a><span class="sd">        Type number is valid for arbitrary ints or floats:</span>
+</span><span id="MessageTemplate-629"><a href="#MessageTemplate-629"><span class="linenos">629</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;number&#39;}})</span>
+</span><span id="MessageTemplate-630"><a href="#MessageTemplate-630"><span class="linenos">630</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="MessageTemplate-631"><a href="#MessageTemplate-631"><span class="linenos">631</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-632"><a href="#MessageTemplate-632"><span class="linenos">632</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))</span>
+</span><span id="MessageTemplate-633"><a href="#MessageTemplate-633"><span class="linenos">633</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-634"><a href="#MessageTemplate-634"><span class="linenos">634</span></a>
+</span><span id="MessageTemplate-635"><a href="#MessageTemplate-635"><span class="linenos">635</span></a><span class="sd">        All keys in template have to be present in message:</span>
+</span><span id="MessageTemplate-636"><a href="#MessageTemplate-636"><span class="linenos">636</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate-637"><a href="#MessageTemplate-637"><span class="linenos">637</span></a><span class="sd">        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate-638"><a href="#MessageTemplate-638"><span class="linenos">638</span></a><span class="sd">        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate-639"><a href="#MessageTemplate-639"><span class="linenos">639</span></a><span class="sd">        ...                                &#39;properties&#39;: {</span>
+</span><span id="MessageTemplate-640"><a href="#MessageTemplate-640"><span class="linenos">640</span></a><span class="sd">        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate-641"><a href="#MessageTemplate-641"><span class="linenos">641</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True,</span>
+</span><span id="MessageTemplate-642"><a href="#MessageTemplate-642"><span class="linenos">642</span></a><span class="sd">        ...                                    &#39;key 3&#39;: False}}})</span>
+</span><span id="MessageTemplate-643"><a href="#MessageTemplate-643"><span class="linenos">643</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate-644"><a href="#MessageTemplate-644"><span class="linenos">644</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;}))</span>
+</span><span id="MessageTemplate-645"><a href="#MessageTemplate-645"><span class="linenos">645</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate-646"><a href="#MessageTemplate-646"><span class="linenos">646</span></a>
+</span><span id="MessageTemplate-647"><a href="#MessageTemplate-647"><span class="linenos">647</span></a><span class="sd">        But for nested objects their properties do not necessarily have</span>
+</span><span id="MessageTemplate-648"><a href="#MessageTemplate-648"><span class="linenos">648</span></a><span class="sd">        to be present:</span>
+</span><span id="MessageTemplate-649"><a href="#MessageTemplate-649"><span class="linenos">649</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate-650"><a href="#MessageTemplate-650"><span class="linenos">650</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate-651"><a href="#MessageTemplate-651"><span class="linenos">651</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42}}))</span>
+</span><span id="MessageTemplate-652"><a href="#MessageTemplate-652"><span class="linenos">652</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-653"><a href="#MessageTemplate-653"><span class="linenos">653</span></a>
+</span><span id="MessageTemplate-654"><a href="#MessageTemplate-654"><span class="linenos">654</span></a><span class="sd">        Schema True matches everything (even None):</span>
+</span><span id="MessageTemplate-655"><a href="#MessageTemplate-655"><span class="linenos">655</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate-656"><a href="#MessageTemplate-656"><span class="linenos">656</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate-657"><a href="#MessageTemplate-657"><span class="linenos">657</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 2&#39;: None}}))</span>
+</span><span id="MessageTemplate-658"><a href="#MessageTemplate-658"><span class="linenos">658</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-659"><a href="#MessageTemplate-659"><span class="linenos">659</span></a>
+</span><span id="MessageTemplate-660"><a href="#MessageTemplate-660"><span class="linenos">660</span></a><span class="sd">        Schema False matches nothing:</span>
+</span><span id="MessageTemplate-661"><a href="#MessageTemplate-661"><span class="linenos">661</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate-662"><a href="#MessageTemplate-662"><span class="linenos">662</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate-663"><a href="#MessageTemplate-663"><span class="linenos">663</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 3&#39;: True}}))</span>
+</span><span id="MessageTemplate-664"><a href="#MessageTemplate-664"><span class="linenos">664</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate-665"><a href="#MessageTemplate-665"><span class="linenos">665</span></a>
+</span><span id="MessageTemplate-666"><a href="#MessageTemplate-666"><span class="linenos">666</span></a><span class="sd">        Message is valid for the constant template created from it:</span>
+</span><span id="MessageTemplate-667"><a href="#MessageTemplate-667"><span class="linenos">667</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},</span>
+</span><span id="MessageTemplate-668"><a href="#MessageTemplate-668"><span class="linenos">668</span></a><span class="sd">        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})</span>
+</span><span id="MessageTemplate-669"><a href="#MessageTemplate-669"><span class="linenos">669</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="MessageTemplate-670"><a href="#MessageTemplate-670"><span class="linenos">670</span></a><span class="sd">        &gt;&gt;&gt; t.check(m)</span>
+</span><span id="MessageTemplate-671"><a href="#MessageTemplate-671"><span class="linenos">671</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate-672"><a href="#MessageTemplate-672"><span class="linenos">672</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate-673"><a href="#MessageTemplate-673"><span class="linenos">673</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="MessageTemplate-674"><a href="#MessageTemplate-674"><span class="linenos">674</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="MessageTemplate-675"><a href="#MessageTemplate-675"><span class="linenos">675</span></a>                <span class="k">return</span> <span class="kc">False</span>
+</span><span id="MessageTemplate-676"><a href="#MessageTemplate-676"><span class="linenos">676</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="MessageTemplate-677"><a href="#MessageTemplate-677"><span class="linenos">677</span></a>                <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
+</span><span id="MessageTemplate-678"><a href="#MessageTemplate-678"><span class="linenos">678</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="MessageTemplate-679"><a href="#MessageTemplate-679"><span class="linenos">679</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="MessageTemplate-680"><a href="#MessageTemplate-680"><span class="linenos">680</span></a>        <span class="k">return</span> <span class="kc">True</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Define a message template.</p>
+
+<p>A message template is a mapping from string keys to JSON schemas as
+values:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                     <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="p">[</span><span class="s1">&#39;key 3&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;object&#39;</span><span class="p">,</span>
+<span class="gp">... </span>              <span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;number&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                             <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}}</span>
+</code></pre>
+</div>
+
+<p>A message template matches a message if all keys of the template are
+contained in the message and the values in the message validate against
+the respective schemas:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;some string&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">}}))</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>An empty mapping therefore matches all messages:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;arbitrary&#39;</span><span class="p">:</span> <span class="s1">&#39;content&#39;</span><span class="p">}))</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="MessageTemplate.__init__" class="classattr">
+                                        <input id="MessageTemplate.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="name">MessageTemplate</span><span class="signature pdoc-code multiline">(<span class="param">     <span class="n">init</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span></span>)</span>
+
+                <label class="view-source-button" for="MessageTemplate.__init__-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageTemplate.__init__"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageTemplate.__init__-400"><a href="#MessageTemplate.__init__-400"><span class="linenos">400</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">init</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">JSONSchema</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate.__init__-401"><a href="#MessageTemplate.__init__-401"><span class="linenos">401</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise message.</span>
+</span><span id="MessageTemplate.__init__-402"><a href="#MessageTemplate.__init__-402"><span class="linenos">402</span></a>
+</span><span id="MessageTemplate.__init__-403"><a href="#MessageTemplate.__init__-403"><span class="linenos">403</span></a><span class="sd">        Template is initialised empty or with given key-value pairs:</span>
+</span><span id="MessageTemplate.__init__-404"><a href="#MessageTemplate.__init__-404"><span class="linenos">404</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate.__init__-405"><a href="#MessageTemplate.__init__-405"><span class="linenos">405</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="MessageTemplate.__init__-406"><a href="#MessageTemplate.__init__-406"><span class="linenos">406</span></a><span class="sd">        {}</span>
+</span><span id="MessageTemplate.__init__-407"><a href="#MessageTemplate.__init__-407"><span class="linenos">407</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})</span>
+</span><span id="MessageTemplate.__init__-408"><a href="#MessageTemplate.__init__-408"><span class="linenos">408</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="MessageTemplate.__init__-409"><a href="#MessageTemplate.__init__-409"><span class="linenos">409</span></a><span class="sd">        {&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</span><span id="MessageTemplate.__init__-410"><a href="#MessageTemplate.__init__-410"><span class="linenos">410</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate.__init__-411"><a href="#MessageTemplate.__init__-411"><span class="linenos">411</span></a>        <span class="k">if</span> <span class="n">init</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate.__init__-412"><a href="#MessageTemplate.__init__-412"><span class="linenos">412</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">init</span><span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Initialise message.</p>
+
+<p>Template is initialised empty or with given key-value pairs:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
+<span class="go">{}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
+<span class="go">{&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageTemplate.from_message" class="classattr">
+                                        <input id="MessageTemplate.from_message-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+                    <div class="decorator decorator-staticmethod">@staticmethod</div>
+
+        <span class="def">def</span>
+        <span class="name">from_message</span><span class="signature pdoc-code multiline">(<span class="param">        <span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="n"><a href="#MessageTemplate">MessageTemplate</a></span>:</span></span>
+
+                <label class="view-source-button" for="MessageTemplate.from_message-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageTemplate.from_message"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageTemplate.from_message-414"><a href="#MessageTemplate.from_message-414"><span class="linenos">414</span></a>    <span class="nd">@staticmethod</span>
+</span><span id="MessageTemplate.from_message-415"><a href="#MessageTemplate.from_message-415"><span class="linenos">415</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">from_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;MessageTemplate&quot;</span><span class="p">:</span>
+</span><span id="MessageTemplate.from_message-416"><a href="#MessageTemplate.from_message-416"><span class="linenos">416</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Create template from message.</span>
+</span><span id="MessageTemplate.from_message-417"><a href="#MessageTemplate.from_message-417"><span class="linenos">417</span></a>
+</span><span id="MessageTemplate.from_message-418"><a href="#MessageTemplate.from_message-418"><span class="linenos">418</span></a><span class="sd">        Template witch constant schemas is created from message:</span>
+</span><span id="MessageTemplate.from_message-419"><a href="#MessageTemplate.from_message-419"><span class="linenos">419</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;})</span>
+</span><span id="MessageTemplate.from_message-420"><a href="#MessageTemplate.from_message-420"><span class="linenos">420</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="MessageTemplate.from_message-421"><a href="#MessageTemplate.from_message-421"><span class="linenos">421</span></a><span class="sd">        &gt;&gt;&gt; print(t)</span>
+</span><span id="MessageTemplate.from_message-422"><a href="#MessageTemplate.from_message-422"><span class="linenos">422</span></a><span class="sd">        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+</span><span id="MessageTemplate.from_message-423"><a href="#MessageTemplate.from_message-423"><span class="linenos">423</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},</span>
+</span><span id="MessageTemplate.from_message-424"><a href="#MessageTemplate.from_message-424"><span class="linenos">424</span></a><span class="sd">        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})</span>
+</span><span id="MessageTemplate.from_message-425"><a href="#MessageTemplate.from_message-425"><span class="linenos">425</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="MessageTemplate.from_message-426"><a href="#MessageTemplate.from_message-426"><span class="linenos">426</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.from_message-427"><a href="#MessageTemplate.from_message-427"><span class="linenos">427</span></a><span class="sd">        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},</span>
+</span><span id="MessageTemplate.from_message-428"><a href="#MessageTemplate.from_message-428"><span class="linenos">428</span></a><span class="sd">         &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.from_message-429"><a href="#MessageTemplate.from_message-429"><span class="linenos">429</span></a><span class="sd">                  &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="MessageTemplate.from_message-430"><a href="#MessageTemplate.from_message-430"><span class="linenos">430</span></a><span class="sd">                                 &#39;float&#39;: {&#39;const&#39;: 42.42}}},</span>
+</span><span id="MessageTemplate.from_message-431"><a href="#MessageTemplate.from_message-431"><span class="linenos">431</span></a><span class="sd">         &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+</span><span id="MessageTemplate.from_message-432"><a href="#MessageTemplate.from_message-432"><span class="linenos">432</span></a><span class="sd">                  &#39;items&#39;: [{&#39;const&#39;: None},</span>
+</span><span id="MessageTemplate.from_message-433"><a href="#MessageTemplate.from_message-433"><span class="linenos">433</span></a><span class="sd">                            {&#39;const&#39;: True},</span>
+</span><span id="MessageTemplate.from_message-434"><a href="#MessageTemplate.from_message-434"><span class="linenos">434</span></a><span class="sd">                            {&#39;const&#39;: &#39;string&#39;}]}}</span>
+</span><span id="MessageTemplate.from_message-435"><a href="#MessageTemplate.from_message-435"><span class="linenos">435</span></a>
+</span><span id="MessageTemplate.from_message-436"><a href="#MessageTemplate.from_message-436"><span class="linenos">436</span></a><span class="sd">        This is especially useful for clients that send certain fully</span>
+</span><span id="MessageTemplate.from_message-437"><a href="#MessageTemplate.from_message-437"><span class="linenos">437</span></a><span class="sd">        predefined messages, where the message is given in the configuration</span>
+</span><span id="MessageTemplate.from_message-438"><a href="#MessageTemplate.from_message-438"><span class="linenos">438</span></a><span class="sd">        and the template for the registration can be constructed by this</span>
+</span><span id="MessageTemplate.from_message-439"><a href="#MessageTemplate.from_message-439"><span class="linenos">439</span></a><span class="sd">        method.</span>
+</span><span id="MessageTemplate.from_message-440"><a href="#MessageTemplate.from_message-440"><span class="linenos">440</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate.from_message-441"><a href="#MessageTemplate.from_message-441"><span class="linenos">441</span></a>
+</span><span id="MessageTemplate.from_message-442"><a href="#MessageTemplate.from_message-442"><span class="linenos">442</span></a>        <span class="k">def</span><span class="w"> </span><span class="nf">schema_from_value</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="n">MessageValue</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">JSONSchema</span><span class="p">:</span>
+</span><span id="MessageTemplate.from_message-443"><a href="#MessageTemplate.from_message-443"><span class="linenos">443</span></a>            <span class="n">schema</span><span class="p">:</span> <span class="n">JSONSchema</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="MessageTemplate.from_message-444"><a href="#MessageTemplate.from_message-444"><span class="linenos">444</span></a>            <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate.from_message-445"><a href="#MessageTemplate.from_message-445"><span class="linenos">445</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span>
+</span><span id="MessageTemplate.from_message-446"><a href="#MessageTemplate.from_message-446"><span class="linenos">446</span></a>            <span class="k">elif</span> <span class="p">(</span>
+</span><span id="MessageTemplate.from_message-447"><a href="#MessageTemplate.from_message-447"><span class="linenos">447</span></a>                <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="MessageTemplate.from_message-448"><a href="#MessageTemplate.from_message-448"><span class="linenos">448</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
+</span><span id="MessageTemplate.from_message-449"><a href="#MessageTemplate.from_message-449"><span class="linenos">449</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">)</span>
+</span><span id="MessageTemplate.from_message-450"><a href="#MessageTemplate.from_message-450"><span class="linenos">450</span></a>                <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="MessageTemplate.from_message-451"><a href="#MessageTemplate.from_message-451"><span class="linenos">451</span></a>            <span class="p">):</span>
+</span><span id="MessageTemplate.from_message-452"><a href="#MessageTemplate.from_message-452"><span class="linenos">452</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">value</span><span class="p">}</span>
+</span><span id="MessageTemplate.from_message-453"><a href="#MessageTemplate.from_message-453"><span class="linenos">453</span></a>            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+</span><span id="MessageTemplate.from_message-454"><a href="#MessageTemplate.from_message-454"><span class="linenos">454</span></a>                <span class="n">properties</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="MessageTemplate.from_message-455"><a href="#MessageTemplate.from_message-455"><span class="linenos">455</span></a>                <span class="k">for</span> <span class="n">inner_key</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
+</span><span id="MessageTemplate.from_message-456"><a href="#MessageTemplate.from_message-456"><span class="linenos">456</span></a>                    <span class="n">inner_value</span><span class="p">:</span> <span class="n">Message</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="n">inner_key</span><span class="p">]</span>
+</span><span id="MessageTemplate.from_message-457"><a href="#MessageTemplate.from_message-457"><span class="linenos">457</span></a>                    <span class="n">properties</span><span class="p">[</span><span class="n">inner_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">schema_from_value</span><span class="p">(</span><span class="n">inner_value</span><span class="p">)</span>
+</span><span id="MessageTemplate.from_message-458"><a href="#MessageTemplate.from_message-458"><span class="linenos">458</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">,</span> <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="n">properties</span><span class="p">}</span>
+</span><span id="MessageTemplate.from_message-459"><a href="#MessageTemplate.from_message-459"><span class="linenos">459</span></a>            <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="MessageTemplate.from_message-460"><a href="#MessageTemplate.from_message-460"><span class="linenos">460</span></a>                <span class="n">schema</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="MessageTemplate.from_message-461"><a href="#MessageTemplate.from_message-461"><span class="linenos">461</span></a>                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="MessageTemplate.from_message-462"><a href="#MessageTemplate.from_message-462"><span class="linenos">462</span></a>                    <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">schema_from_value</span><span class="p">(</span><span class="n">element</span><span class="p">)</span> <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">value</span><span class="p">],</span>
+</span><span id="MessageTemplate.from_message-463"><a href="#MessageTemplate.from_message-463"><span class="linenos">463</span></a>                <span class="p">}</span>
+</span><span id="MessageTemplate.from_message-464"><a href="#MessageTemplate.from_message-464"><span class="linenos">464</span></a>            <span class="k">return</span> <span class="n">schema</span>
+</span><span id="MessageTemplate.from_message-465"><a href="#MessageTemplate.from_message-465"><span class="linenos">465</span></a>
+</span><span id="MessageTemplate.from_message-466"><a href="#MessageTemplate.from_message-466"><span class="linenos">466</span></a>        <span class="n">template</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+</span><span id="MessageTemplate.from_message-467"><a href="#MessageTemplate.from_message-467"><span class="linenos">467</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="MessageTemplate.from_message-468"><a href="#MessageTemplate.from_message-468"><span class="linenos">468</span></a>            <span class="n">template</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">schema_from_value</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
+</span><span id="MessageTemplate.from_message-469"><a href="#MessageTemplate.from_message-469"><span class="linenos">469</span></a>        <span class="k">return</span> <span class="n">template</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Create template from message.</p>
+
+<p>Template witch constant schemas is created from message:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n"><a href="#MessageTemplate.from_message">MessageTemplate.from_message</a></span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
+<span class="go">{&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;dict&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;int&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s1">&#39;float&#39;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">},</span>
+<span class="gp">... </span>                               <span class="s1">&#39;list&#39;</span><span class="p">:</span> <span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;string&#39;</span><span class="p">]})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n"><a href="#MessageTemplate.from_message">MessageTemplate.from_message</a></span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">{&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},</span>
+<span class="go"> &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+<span class="go">          &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},</span>
+<span class="go">                         &#39;float&#39;: {&#39;const&#39;: 42.42}}},</span>
+<span class="go"> &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+<span class="go">          &#39;items&#39;: [{&#39;const&#39;: None},</span>
+<span class="go">                    {&#39;const&#39;: True},</span>
+<span class="go">                    {&#39;const&#39;: &#39;string&#39;}]}}</span>
+</code></pre>
+</div>
+
+<p>This is especially useful for clients that send certain fully
+predefined messages, where the message is given in the configuration
+and the template for the registration can be constructed by this
+method.</p>
+</div>
+
+
+                            </div>
+                            <div id="MessageTemplate.update" class="classattr">
+                                        <input id="MessageTemplate.update-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">update</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="o">*</span><span class="n">args</span>, </span><span class="param"><span class="o">**</span><span class="n">kwargs</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="MessageTemplate.update-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageTemplate.update"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageTemplate.update-507"><a href="#MessageTemplate.update-507"><span class="linenos">507</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate.update-508"><a href="#MessageTemplate.update-508"><span class="linenos">508</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override update to use validity checks.</span>
+</span><span id="MessageTemplate.update-509"><a href="#MessageTemplate.update-509"><span class="linenos">509</span></a>
+</span><span id="MessageTemplate.update-510"><a href="#MessageTemplate.update-510"><span class="linenos">510</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate.update-511"><a href="#MessageTemplate.update-511"><span class="linenos">511</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate.update-512"><a href="#MessageTemplate.update-512"><span class="linenos">512</span></a><span class="sd">        ...           &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate.update-513"><a href="#MessageTemplate.update-513"><span class="linenos">513</span></a><span class="sd">        ...           &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.update-514"><a href="#MessageTemplate.update-514"><span class="linenos">514</span></a><span class="sd">        ...                     &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.update-515"><a href="#MessageTemplate.update-515"><span class="linenos">515</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True}}})</span>
+</span><span id="MessageTemplate.update-516"><a href="#MessageTemplate.update-516"><span class="linenos">516</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.update-517"><a href="#MessageTemplate.update-517"><span class="linenos">517</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate.update-518"><a href="#MessageTemplate.update-518"><span class="linenos">518</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.update-519"><a href="#MessageTemplate.update-519"><span class="linenos">519</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.update-520"><a href="#MessageTemplate.update-520"><span class="linenos">520</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="MessageTemplate.update-521"><a href="#MessageTemplate.update-521"><span class="linenos">521</span></a><span class="sd">        &gt;&gt;&gt; t.update({42: {&#39;const&#39;: &#39;int key&#39;}})</span>
+</span><span id="MessageTemplate.update-522"><a href="#MessageTemplate.update-522"><span class="linenos">522</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate.update-523"><a href="#MessageTemplate.update-523"><span class="linenos">523</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate.update-524"><a href="#MessageTemplate.update-524"><span class="linenos">524</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate.update-525"><a href="#MessageTemplate.update-525"><span class="linenos">525</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key&#39;: &#39;schema&#39;})  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.update-526"><a href="#MessageTemplate.update-526"><span class="linenos">526</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate.update-527"><a href="#MessageTemplate.update-527"><span class="linenos">527</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate.update-528"><a href="#MessageTemplate.update-528"><span class="linenos">528</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate.update-529"><a href="#MessageTemplate.update-529"><span class="linenos">529</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate.update-530"><a href="#MessageTemplate.update-530"><span class="linenos">530</span></a><span class="sd">        &gt;&gt;&gt; t.update({&#39;key&#39;: True})</span>
+</span><span id="MessageTemplate.update-531"><a href="#MessageTemplate.update-531"><span class="linenos">531</span></a>
+</span><span id="MessageTemplate.update-532"><a href="#MessageTemplate.update-532"><span class="linenos">532</span></a><span class="sd">        This is also used in __init__:</span>
+</span><span id="MessageTemplate.update-533"><a href="#MessageTemplate.update-533"><span class="linenos">533</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate.update-534"><a href="#MessageTemplate.update-534"><span class="linenos">534</span></a><span class="sd">        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate.update-535"><a href="#MessageTemplate.update-535"><span class="linenos">535</span></a><span class="sd">        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.update-536"><a href="#MessageTemplate.update-536"><span class="linenos">536</span></a><span class="sd">        ...                                &#39;properties&#39;: {</span>
+</span><span id="MessageTemplate.update-537"><a href="#MessageTemplate.update-537"><span class="linenos">537</span></a><span class="sd">        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.update-538"><a href="#MessageTemplate.update-538"><span class="linenos">538</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True}}})</span>
+</span><span id="MessageTemplate.update-539"><a href="#MessageTemplate.update-539"><span class="linenos">539</span></a><span class="sd">        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.update-540"><a href="#MessageTemplate.update-540"><span class="linenos">540</span></a><span class="sd">        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate.update-541"><a href="#MessageTemplate.update-541"><span class="linenos">541</span></a><span class="sd">         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.update-542"><a href="#MessageTemplate.update-542"><span class="linenos">542</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.update-543"><a href="#MessageTemplate.update-543"><span class="linenos">543</span></a><span class="sd">                                  &#39;key 2&#39;: True}}}</span>
+</span><span id="MessageTemplate.update-544"><a href="#MessageTemplate.update-544"><span class="linenos">544</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({42: {&#39;const&#39;: &#39;int key&#39;}})</span>
+</span><span id="MessageTemplate.update-545"><a href="#MessageTemplate.update-545"><span class="linenos">545</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate.update-546"><a href="#MessageTemplate.update-546"><span class="linenos">546</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate.update-547"><a href="#MessageTemplate.update-547"><span class="linenos">547</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate.update-548"><a href="#MessageTemplate.update-548"><span class="linenos">548</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: &#39;schema&#39;})</span>
+</span><span id="MessageTemplate.update-549"><a href="#MessageTemplate.update-549"><span class="linenos">549</span></a><span class="sd">        ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.update-550"><a href="#MessageTemplate.update-550"><span class="linenos">550</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate.update-551"><a href="#MessageTemplate.update-551"><span class="linenos">551</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate.update-552"><a href="#MessageTemplate.update-552"><span class="linenos">552</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate.update-553"><a href="#MessageTemplate.update-553"><span class="linenos">553</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate.update-554"><a href="#MessageTemplate.update-554"><span class="linenos">554</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: True})</span>
+</span><span id="MessageTemplate.update-555"><a href="#MessageTemplate.update-555"><span class="linenos">555</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate.update-556"><a href="#MessageTemplate.update-556"><span class="linenos">556</span></a>        <span class="k">if</span> <span class="n">args</span><span class="p">:</span>
+</span><span id="MessageTemplate.update-557"><a href="#MessageTemplate.update-557"><span class="linenos">557</span></a>            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+</span><span id="MessageTemplate.update-558"><a href="#MessageTemplate.update-558"><span class="linenos">558</span></a>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;update expected at most 1 argument, got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="MessageTemplate.update-559"><a href="#MessageTemplate.update-559"><span class="linenos">559</span></a>            <span class="n">other</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+</span><span id="MessageTemplate.update-560"><a href="#MessageTemplate.update-560"><span class="linenos">560</span></a>            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">other</span><span class="p">:</span>
+</span><span id="MessageTemplate.update-561"><a href="#MessageTemplate.update-561"><span class="linenos">561</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">other</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="MessageTemplate.update-562"><a href="#MessageTemplate.update-562"><span class="linenos">562</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">kwargs</span><span class="p">:</span>
+</span><span id="MessageTemplate.update-563"><a href="#MessageTemplate.update-563"><span class="linenos">563</span></a>            <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Override update to use validity checks.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;object&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;number&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                                   <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">{&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+<span class="go"> &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+<span class="go">           &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+<span class="go">                          &#39;key 2&#39;: True}}}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="mi">42</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;int key&#39;</span><span class="p">}})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;schema&#39;</span><span class="p">})</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;schema&#39; is not a valid value in MessageTemplate</span>
+<span class="x">(not a valid JSON schema).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">})</span>
+</code></pre>
+</div>
+
+<p>This is also used in __init__:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                     <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                     <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;object&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                               <span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span>
+<span class="gp">... </span>                                   <span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;number&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                                   <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">{&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+<span class="go"> &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+<span class="go">           &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+<span class="go">                          &#39;key 2&#39;: True}}}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="mi">42</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;int key&#39;</span><span class="p">}})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;schema&#39;</span><span class="p">})</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;schema&#39; is not a valid value in MessageTemplate</span>
+<span class="x">(not a valid JSON schema).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">})</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageTemplate.setdefault" class="classattr">
+                                        <input id="MessageTemplate.setdefault-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">setdefault</span><span class="signature pdoc-code multiline">(<span class="param">  <span class="bp">self</span>,</span><span class="param">        <span class="n">key</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">      <span class="n">value</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="kc">None</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="nb">bool</span> <span class="o">|</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">]]</span>:</span></span>
+
+                <label class="view-source-button" for="MessageTemplate.setdefault-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageTemplate.setdefault"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageTemplate.setdefault-565"><a href="#MessageTemplate.setdefault-565"><span class="linenos">565</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">JSONSchema</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">JSONSchema</span><span class="p">:</span>
+</span><span id="MessageTemplate.setdefault-566"><a href="#MessageTemplate.setdefault-566"><span class="linenos">566</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Override setdefault to use validity checks.</span>
+</span><span id="MessageTemplate.setdefault-567"><a href="#MessageTemplate.setdefault-567"><span class="linenos">567</span></a>
+</span><span id="MessageTemplate.setdefault-568"><a href="#MessageTemplate.setdefault-568"><span class="linenos">568</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate()</span>
+</span><span id="MessageTemplate.setdefault-569"><a href="#MessageTemplate.setdefault-569"><span class="linenos">569</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, {&#39;const&#39;: &#39;value&#39;})</span>
+</span><span id="MessageTemplate.setdefault-570"><a href="#MessageTemplate.setdefault-570"><span class="linenos">570</span></a><span class="sd">        {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="MessageTemplate.setdefault-571"><a href="#MessageTemplate.setdefault-571"><span class="linenos">571</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 2&#39;, {&#39;type&#39;: &#39;string&#39;})</span>
+</span><span id="MessageTemplate.setdefault-572"><a href="#MessageTemplate.setdefault-572"><span class="linenos">572</span></a><span class="sd">        {&#39;type&#39;: &#39;string&#39;}</span>
+</span><span id="MessageTemplate.setdefault-573"><a href="#MessageTemplate.setdefault-573"><span class="linenos">573</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 3&#39;, {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.setdefault-574"><a href="#MessageTemplate.setdefault-574"><span class="linenos">574</span></a><span class="sd">        ...                        &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.setdefault-575"><a href="#MessageTemplate.setdefault-575"><span class="linenos">575</span></a><span class="sd">        ...                                       &#39;key 2&#39;: True}})</span>
+</span><span id="MessageTemplate.setdefault-576"><a href="#MessageTemplate.setdefault-576"><span class="linenos">576</span></a><span class="sd">        ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.setdefault-577"><a href="#MessageTemplate.setdefault-577"><span class="linenos">577</span></a><span class="sd">        {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.setdefault-578"><a href="#MessageTemplate.setdefault-578"><span class="linenos">578</span></a><span class="sd">                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.setdefault-579"><a href="#MessageTemplate.setdefault-579"><span class="linenos">579</span></a><span class="sd">                                  &#39;key 2&#39;: True}}</span>
+</span><span id="MessageTemplate.setdefault-580"><a href="#MessageTemplate.setdefault-580"><span class="linenos">580</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(42, {&#39;const&#39;: &#39;int key&#39;})</span>
+</span><span id="MessageTemplate.setdefault-581"><a href="#MessageTemplate.setdefault-581"><span class="linenos">581</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate.setdefault-582"><a href="#MessageTemplate.setdefault-582"><span class="linenos">582</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate.setdefault-583"><a href="#MessageTemplate.setdefault-583"><span class="linenos">583</span></a><span class="sd">        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+</span><span id="MessageTemplate.setdefault-584"><a href="#MessageTemplate.setdefault-584"><span class="linenos">584</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key&#39;, &#39;schema&#39;)  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageTemplate.setdefault-585"><a href="#MessageTemplate.setdefault-585"><span class="linenos">585</span></a><span class="sd">        Traceback (most recent call last):</span>
+</span><span id="MessageTemplate.setdefault-586"><a href="#MessageTemplate.setdefault-586"><span class="linenos">586</span></a><span class="sd">          ...</span>
+</span><span id="MessageTemplate.setdefault-587"><a href="#MessageTemplate.setdefault-587"><span class="linenos">587</span></a><span class="sd">        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate</span>
+</span><span id="MessageTemplate.setdefault-588"><a href="#MessageTemplate.setdefault-588"><span class="linenos">588</span></a><span class="sd">        (not a valid JSON schema).</span>
+</span><span id="MessageTemplate.setdefault-589"><a href="#MessageTemplate.setdefault-589"><span class="linenos">589</span></a>
+</span><span id="MessageTemplate.setdefault-590"><a href="#MessageTemplate.setdefault-590"><span class="linenos">590</span></a><span class="sd">        But __setitem__ is not called if the key is already present:</span>
+</span><span id="MessageTemplate.setdefault-591"><a href="#MessageTemplate.setdefault-591"><span class="linenos">591</span></a><span class="sd">        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, &#39;schema&#39;)</span>
+</span><span id="MessageTemplate.setdefault-592"><a href="#MessageTemplate.setdefault-592"><span class="linenos">592</span></a><span class="sd">        {&#39;const&#39;: &#39;value&#39;}</span>
+</span><span id="MessageTemplate.setdefault-593"><a href="#MessageTemplate.setdefault-593"><span class="linenos">593</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate.setdefault-594"><a href="#MessageTemplate.setdefault-594"><span class="linenos">594</span></a>        <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="MessageTemplate.setdefault-595"><a href="#MessageTemplate.setdefault-595"><span class="linenos">595</span></a>            <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageTemplate.setdefault-596"><a href="#MessageTemplate.setdefault-596"><span class="linenos">596</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+</span><span id="MessageTemplate.setdefault-597"><a href="#MessageTemplate.setdefault-597"><span class="linenos">597</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="MessageTemplate.setdefault-598"><a href="#MessageTemplate.setdefault-598"><span class="linenos">598</span></a>                <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="MessageTemplate.setdefault-599"><a href="#MessageTemplate.setdefault-599"><span class="linenos">599</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Override setdefault to use validity checks.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key 1&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">})</span>
+<span class="go">{&#39;const&#39;: &#39;value&#39;}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key 2&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">})</span>
+<span class="go">{&#39;type&#39;: &#39;string&#39;}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key 3&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;object&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                       <span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;number&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                                      <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}})</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">{&#39;type&#39;: &#39;object&#39;,</span>
+<span class="go">           &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+<span class="go">                          &#39;key 2&#39;: True}}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;int key&#39;</span><span class="p">})</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key&#39;</span><span class="p">,</span> <span class="s1">&#39;schema&#39;</span><span class="p">)</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="gt">Traceback (most recent call last):</span>
+<span class="w">  </span><span class="c">...</span>
+<span class="gr">TypeError</span>: <span class="n">&#39;schema&#39; is not a valid value in MessageTemplate</span>
+<span class="x">(not a valid JSON schema).</span>
+</code></pre>
+</div>
+
+<p>But __setitem__ is not called if the key is already present:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">&#39;key 1&#39;</span><span class="p">,</span> <span class="s1">&#39;schema&#39;</span><span class="p">)</span>
+<span class="go">{&#39;const&#39;: &#39;value&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageTemplate.check" class="classattr">
+                                        <input id="MessageTemplate.check-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">check</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="nb">bool</span>:</span></span>
+
+                <label class="view-source-button" for="MessageTemplate.check-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageTemplate.check"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageTemplate.check-601"><a href="#MessageTemplate.check-601"><span class="linenos">601</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="MessageTemplate.check-602"><a href="#MessageTemplate.check-602"><span class="linenos">602</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Check message against this template.</span>
+</span><span id="MessageTemplate.check-603"><a href="#MessageTemplate.check-603"><span class="linenos">603</span></a>
+</span><span id="MessageTemplate.check-604"><a href="#MessageTemplate.check-604"><span class="linenos">604</span></a><span class="sd">        Constant values have to match exactly:</span>
+</span><span id="MessageTemplate.check-605"><a href="#MessageTemplate.check-605"><span class="linenos">605</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})</span>
+</span><span id="MessageTemplate.check-606"><a href="#MessageTemplate.check-606"><span class="linenos">606</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;}))</span>
+</span><span id="MessageTemplate.check-607"><a href="#MessageTemplate.check-607"><span class="linenos">607</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-608"><a href="#MessageTemplate.check-608"><span class="linenos">608</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;other value&#39;}))</span>
+</span><span id="MessageTemplate.check-609"><a href="#MessageTemplate.check-609"><span class="linenos">609</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate.check-610"><a href="#MessageTemplate.check-610"><span class="linenos">610</span></a>
+</span><span id="MessageTemplate.check-611"><a href="#MessageTemplate.check-611"><span class="linenos">611</span></a><span class="sd">        But for integers, floats with the same value are also valid:</span>
+</span><span id="MessageTemplate.check-612"><a href="#MessageTemplate.check-612"><span class="linenos">612</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: 42}})</span>
+</span><span id="MessageTemplate.check-613"><a href="#MessageTemplate.check-613"><span class="linenos">613</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="MessageTemplate.check-614"><a href="#MessageTemplate.check-614"><span class="linenos">614</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-615"><a href="#MessageTemplate.check-615"><span class="linenos">615</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))</span>
+</span><span id="MessageTemplate.check-616"><a href="#MessageTemplate.check-616"><span class="linenos">616</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-617"><a href="#MessageTemplate.check-617"><span class="linenos">617</span></a>
+</span><span id="MessageTemplate.check-618"><a href="#MessageTemplate.check-618"><span class="linenos">618</span></a><span class="sd">        Type integer is valid for floats with zero fractional part, but</span>
+</span><span id="MessageTemplate.check-619"><a href="#MessageTemplate.check-619"><span class="linenos">619</span></a><span class="sd">        not by floats with non-zero fractional part:</span>
+</span><span id="MessageTemplate.check-620"><a href="#MessageTemplate.check-620"><span class="linenos">620</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;integer&#39;}})</span>
+</span><span id="MessageTemplate.check-621"><a href="#MessageTemplate.check-621"><span class="linenos">621</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="MessageTemplate.check-622"><a href="#MessageTemplate.check-622"><span class="linenos">622</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-623"><a href="#MessageTemplate.check-623"><span class="linenos">623</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))</span>
+</span><span id="MessageTemplate.check-624"><a href="#MessageTemplate.check-624"><span class="linenos">624</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-625"><a href="#MessageTemplate.check-625"><span class="linenos">625</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))</span>
+</span><span id="MessageTemplate.check-626"><a href="#MessageTemplate.check-626"><span class="linenos">626</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate.check-627"><a href="#MessageTemplate.check-627"><span class="linenos">627</span></a>
+</span><span id="MessageTemplate.check-628"><a href="#MessageTemplate.check-628"><span class="linenos">628</span></a><span class="sd">        Type number is valid for arbitrary ints or floats:</span>
+</span><span id="MessageTemplate.check-629"><a href="#MessageTemplate.check-629"><span class="linenos">629</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;number&#39;}})</span>
+</span><span id="MessageTemplate.check-630"><a href="#MessageTemplate.check-630"><span class="linenos">630</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))</span>
+</span><span id="MessageTemplate.check-631"><a href="#MessageTemplate.check-631"><span class="linenos">631</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-632"><a href="#MessageTemplate.check-632"><span class="linenos">632</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))</span>
+</span><span id="MessageTemplate.check-633"><a href="#MessageTemplate.check-633"><span class="linenos">633</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-634"><a href="#MessageTemplate.check-634"><span class="linenos">634</span></a>
+</span><span id="MessageTemplate.check-635"><a href="#MessageTemplate.check-635"><span class="linenos">635</span></a><span class="sd">        All keys in template have to be present in message:</span>
+</span><span id="MessageTemplate.check-636"><a href="#MessageTemplate.check-636"><span class="linenos">636</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},</span>
+</span><span id="MessageTemplate.check-637"><a href="#MessageTemplate.check-637"><span class="linenos">637</span></a><span class="sd">        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>
+</span><span id="MessageTemplate.check-638"><a href="#MessageTemplate.check-638"><span class="linenos">638</span></a><span class="sd">        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>
+</span><span id="MessageTemplate.check-639"><a href="#MessageTemplate.check-639"><span class="linenos">639</span></a><span class="sd">        ...                                &#39;properties&#39;: {</span>
+</span><span id="MessageTemplate.check-640"><a href="#MessageTemplate.check-640"><span class="linenos">640</span></a><span class="sd">        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="MessageTemplate.check-641"><a href="#MessageTemplate.check-641"><span class="linenos">641</span></a><span class="sd">        ...                                    &#39;key 2&#39;: True,</span>
+</span><span id="MessageTemplate.check-642"><a href="#MessageTemplate.check-642"><span class="linenos">642</span></a><span class="sd">        ...                                    &#39;key 3&#39;: False}}})</span>
+</span><span id="MessageTemplate.check-643"><a href="#MessageTemplate.check-643"><span class="linenos">643</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate.check-644"><a href="#MessageTemplate.check-644"><span class="linenos">644</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;}))</span>
+</span><span id="MessageTemplate.check-645"><a href="#MessageTemplate.check-645"><span class="linenos">645</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate.check-646"><a href="#MessageTemplate.check-646"><span class="linenos">646</span></a>
+</span><span id="MessageTemplate.check-647"><a href="#MessageTemplate.check-647"><span class="linenos">647</span></a><span class="sd">        But for nested objects their properties do not necessarily have</span>
+</span><span id="MessageTemplate.check-648"><a href="#MessageTemplate.check-648"><span class="linenos">648</span></a><span class="sd">        to be present:</span>
+</span><span id="MessageTemplate.check-649"><a href="#MessageTemplate.check-649"><span class="linenos">649</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate.check-650"><a href="#MessageTemplate.check-650"><span class="linenos">650</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate.check-651"><a href="#MessageTemplate.check-651"><span class="linenos">651</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42}}))</span>
+</span><span id="MessageTemplate.check-652"><a href="#MessageTemplate.check-652"><span class="linenos">652</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-653"><a href="#MessageTemplate.check-653"><span class="linenos">653</span></a>
+</span><span id="MessageTemplate.check-654"><a href="#MessageTemplate.check-654"><span class="linenos">654</span></a><span class="sd">        Schema True matches everything (even None):</span>
+</span><span id="MessageTemplate.check-655"><a href="#MessageTemplate.check-655"><span class="linenos">655</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate.check-656"><a href="#MessageTemplate.check-656"><span class="linenos">656</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate.check-657"><a href="#MessageTemplate.check-657"><span class="linenos">657</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 2&#39;: None}}))</span>
+</span><span id="MessageTemplate.check-658"><a href="#MessageTemplate.check-658"><span class="linenos">658</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-659"><a href="#MessageTemplate.check-659"><span class="linenos">659</span></a>
+</span><span id="MessageTemplate.check-660"><a href="#MessageTemplate.check-660"><span class="linenos">660</span></a><span class="sd">        Schema False matches nothing:</span>
+</span><span id="MessageTemplate.check-661"><a href="#MessageTemplate.check-661"><span class="linenos">661</span></a><span class="sd">        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,</span>
+</span><span id="MessageTemplate.check-662"><a href="#MessageTemplate.check-662"><span class="linenos">662</span></a><span class="sd">        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,</span>
+</span><span id="MessageTemplate.check-663"><a href="#MessageTemplate.check-663"><span class="linenos">663</span></a><span class="sd">        ...                  &#39;key 3&#39;: {&#39;key 3&#39;: True}}))</span>
+</span><span id="MessageTemplate.check-664"><a href="#MessageTemplate.check-664"><span class="linenos">664</span></a><span class="sd">        False</span>
+</span><span id="MessageTemplate.check-665"><a href="#MessageTemplate.check-665"><span class="linenos">665</span></a>
+</span><span id="MessageTemplate.check-666"><a href="#MessageTemplate.check-666"><span class="linenos">666</span></a><span class="sd">        Message is valid for the constant template created from it:</span>
+</span><span id="MessageTemplate.check-667"><a href="#MessageTemplate.check-667"><span class="linenos">667</span></a><span class="sd">        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},</span>
+</span><span id="MessageTemplate.check-668"><a href="#MessageTemplate.check-668"><span class="linenos">668</span></a><span class="sd">        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})</span>
+</span><span id="MessageTemplate.check-669"><a href="#MessageTemplate.check-669"><span class="linenos">669</span></a><span class="sd">        &gt;&gt;&gt; t = MessageTemplate.from_message(m)</span>
+</span><span id="MessageTemplate.check-670"><a href="#MessageTemplate.check-670"><span class="linenos">670</span></a><span class="sd">        &gt;&gt;&gt; t.check(m)</span>
+</span><span id="MessageTemplate.check-671"><a href="#MessageTemplate.check-671"><span class="linenos">671</span></a><span class="sd">        True</span>
+</span><span id="MessageTemplate.check-672"><a href="#MessageTemplate.check-672"><span class="linenos">672</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageTemplate.check-673"><a href="#MessageTemplate.check-673"><span class="linenos">673</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
+</span><span id="MessageTemplate.check-674"><a href="#MessageTemplate.check-674"><span class="linenos">674</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="MessageTemplate.check-675"><a href="#MessageTemplate.check-675"><span class="linenos">675</span></a>                <span class="k">return</span> <span class="kc">False</span>
+</span><span id="MessageTemplate.check-676"><a href="#MessageTemplate.check-676"><span class="linenos">676</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="MessageTemplate.check-677"><a href="#MessageTemplate.check-677"><span class="linenos">677</span></a>                <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
+</span><span id="MessageTemplate.check-678"><a href="#MessageTemplate.check-678"><span class="linenos">678</span></a>                <span class="k">if</span> <span class="ow">not</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="MessageTemplate.check-679"><a href="#MessageTemplate.check-679"><span class="linenos">679</span></a>                    <span class="k">return</span> <span class="kc">False</span>
+</span><span id="MessageTemplate.check-680"><a href="#MessageTemplate.check-680"><span class="linenos">680</span></a>        <span class="k">return</span> <span class="kc">True</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Check message against this template.</p>
+
+<p>Constant values have to match exactly:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">}))</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="s1">&#39;other value&#39;</span><span class="p">}))</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>But for integers, floats with the same value are also valid:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}))</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mf">42.0</span><span class="p">}))</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Type integer is valid for floats with zero fractional part, but
+not by floats with non-zero fractional part:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}))</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mf">42.0</span><span class="p">}))</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">}))</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>Type number is valid for arbitrary ints or floats:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;number&#39;</span><span class="p">}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}))</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">}))</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>All keys in template have to be present in message:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                     <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                     <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;object&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                               <span class="s1">&#39;properties&#39;</span><span class="p">:</span> <span class="p">{</span>
+<span class="gp">... </span>                                   <span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;number&#39;</span><span class="p">},</span>
+<span class="gp">... </span>                                   <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+<span class="gp">... </span>                                   <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">}}})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;some string&#39;</span><span class="p">}))</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>But for nested objects their properties do not necessarily have
+to be present:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;some string&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}}))</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Schema True matches everything (even None):</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;some string&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">}}))</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+
+<p>Schema False matches nothing:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                <span class="p">{</span><span class="s1">&#39;key 1&#39;</span><span class="p">:</span> <span class="s1">&#39;value&#39;</span><span class="p">,</span> <span class="s1">&#39;key 2&#39;</span><span class="p">:</span> <span class="s1">&#39;some string&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;key 3&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}}))</span>
+<span class="go">False</span>
+</code></pre>
+</div>
+
+<p>Message is valid for the constant template created from it:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">m</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s1">&#39;Example Sender&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;dict&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;int&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s1">&#39;float&#39;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">},</span>
+<span class="gp">... </span>                               <span class="s1">&#39;list&#39;</span><span class="p">:</span> <span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;string&#39;</span><span class="p">]})</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n"><a href="#MessageTemplate.from_message">MessageTemplate.from_message</a></span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                </section>
+                <section id="TemplateRegistry">
+                            <input id="TemplateRegistry-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">TemplateRegistry</span>:
+
+                <label class="view-source-button" for="TemplateRegistry-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry-683"><a href="#TemplateRegistry-683"><span class="linenos"> 683</span></a><span class="k">class</span><span class="w"> </span><span class="nc">TemplateRegistry</span><span class="p">:</span>
+</span><span id="TemplateRegistry-684"><a href="#TemplateRegistry-684"><span class="linenos"> 684</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Manage a collection of message templates with registered clients.</span>
+</span><span id="TemplateRegistry-685"><a href="#TemplateRegistry-685"><span class="linenos"> 685</span></a>
+</span><span id="TemplateRegistry-686"><a href="#TemplateRegistry-686"><span class="linenos"> 686</span></a><span class="sd">    A new TemplateRegistry is created by:</span>
+</span><span id="TemplateRegistry-687"><a href="#TemplateRegistry-687"><span class="linenos"> 687</span></a><span class="sd">    &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-688"><a href="#TemplateRegistry-688"><span class="linenos"> 688</span></a>
+</span><span id="TemplateRegistry-689"><a href="#TemplateRegistry-689"><span class="linenos"> 689</span></a><span class="sd">    Client names (strings) can be registered for message templates, which</span>
+</span><span id="TemplateRegistry-690"><a href="#TemplateRegistry-690"><span class="linenos"> 690</span></a><span class="sd">    are mappings from keys to JSON schemas:</span>
+</span><span id="TemplateRegistry-691"><a href="#TemplateRegistry-691"><span class="linenos"> 691</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="TemplateRegistry-692"><a href="#TemplateRegistry-692"><span class="linenos"> 692</span></a>
+</span><span id="TemplateRegistry-693"><a href="#TemplateRegistry-693"><span class="linenos"> 693</span></a><span class="sd">    The check function checks if the templates registered for a client</span>
+</span><span id="TemplateRegistry-694"><a href="#TemplateRegistry-694"><span class="linenos"> 694</span></a><span class="sd">    match a given message:</span>
+</span><span id="TemplateRegistry-695"><a href="#TemplateRegistry-695"><span class="linenos"> 695</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-696"><a href="#TemplateRegistry-696"><span class="linenos"> 696</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-697"><a href="#TemplateRegistry-697"><span class="linenos"> 697</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 1&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-698"><a href="#TemplateRegistry-698"><span class="linenos"> 698</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-699"><a href="#TemplateRegistry-699"><span class="linenos"> 699</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-700"><a href="#TemplateRegistry-700"><span class="linenos"> 700</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-701"><a href="#TemplateRegistry-701"><span class="linenos"> 701</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-702"><a href="#TemplateRegistry-702"><span class="linenos"> 702</span></a>
+</span><span id="TemplateRegistry-703"><a href="#TemplateRegistry-703"><span class="linenos"> 703</span></a><span class="sd">    Clients can be registered for values validating against arbitrary JSON</span>
+</span><span id="TemplateRegistry-704"><a href="#TemplateRegistry-704"><span class="linenos"> 704</span></a><span class="sd">    schemas, e.g. all values of a certain type:</span>
+</span><span id="TemplateRegistry-705"><a href="#TemplateRegistry-705"><span class="linenos"> 705</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="TemplateRegistry-706"><a href="#TemplateRegistry-706"><span class="linenos"> 706</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-707"><a href="#TemplateRegistry-707"><span class="linenos"> 707</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-708"><a href="#TemplateRegistry-708"><span class="linenos"> 708</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 2&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-709"><a href="#TemplateRegistry-709"><span class="linenos"> 709</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-710"><a href="#TemplateRegistry-710"><span class="linenos"> 710</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-711"><a href="#TemplateRegistry-711"><span class="linenos"> 711</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-712"><a href="#TemplateRegistry-712"><span class="linenos"> 712</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-713"><a href="#TemplateRegistry-713"><span class="linenos"> 713</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry-714"><a href="#TemplateRegistry-714"><span class="linenos"> 714</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-715"><a href="#TemplateRegistry-715"><span class="linenos"> 715</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-716"><a href="#TemplateRegistry-716"><span class="linenos"> 716</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 3&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-717"><a href="#TemplateRegistry-717"><span class="linenos"> 717</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-718"><a href="#TemplateRegistry-718"><span class="linenos"> 718</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-719"><a href="#TemplateRegistry-719"><span class="linenos"> 719</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-720"><a href="#TemplateRegistry-720"><span class="linenos"> 720</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-721"><a href="#TemplateRegistry-721"><span class="linenos"> 721</span></a>
+</span><span id="TemplateRegistry-722"><a href="#TemplateRegistry-722"><span class="linenos"> 722</span></a><span class="sd">    The order of key-value pairs does not have to match the order in the</span>
+</span><span id="TemplateRegistry-723"><a href="#TemplateRegistry-723"><span class="linenos"> 723</span></a><span class="sd">    messages and keys can be left out:</span>
+</span><span id="TemplateRegistry-724"><a href="#TemplateRegistry-724"><span class="linenos"> 724</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry-725"><a href="#TemplateRegistry-725"><span class="linenos"> 725</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-726"><a href="#TemplateRegistry-726"><span class="linenos"> 726</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-727"><a href="#TemplateRegistry-727"><span class="linenos"> 727</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 4&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-728"><a href="#TemplateRegistry-728"><span class="linenos"> 728</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-729"><a href="#TemplateRegistry-729"><span class="linenos"> 729</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-730"><a href="#TemplateRegistry-730"><span class="linenos"> 730</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-731"><a href="#TemplateRegistry-731"><span class="linenos"> 731</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-732"><a href="#TemplateRegistry-732"><span class="linenos"> 732</span></a>
+</span><span id="TemplateRegistry-733"><a href="#TemplateRegistry-733"><span class="linenos"> 733</span></a><span class="sd">    A registration for an empty template matches all messages:</span>
+</span><span id="TemplateRegistry-734"><a href="#TemplateRegistry-734"><span class="linenos"> 734</span></a><span class="sd">    &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="TemplateRegistry-735"><a href="#TemplateRegistry-735"><span class="linenos"> 735</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-736"><a href="#TemplateRegistry-736"><span class="linenos"> 736</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-737"><a href="#TemplateRegistry-737"><span class="linenos"> 737</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 5&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-738"><a href="#TemplateRegistry-738"><span class="linenos"> 738</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-739"><a href="#TemplateRegistry-739"><span class="linenos"> 739</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-740"><a href="#TemplateRegistry-740"><span class="linenos"> 740</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-741"><a href="#TemplateRegistry-741"><span class="linenos"> 741</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-742"><a href="#TemplateRegistry-742"><span class="linenos"> 742</span></a>
+</span><span id="TemplateRegistry-743"><a href="#TemplateRegistry-743"><span class="linenos"> 743</span></a><span class="sd">    A client can be registered for multiple templates:</span>
+</span><span id="TemplateRegistry-744"><a href="#TemplateRegistry-744"><span class="linenos"> 744</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)</span>
+</span><span id="TemplateRegistry-745"><a href="#TemplateRegistry-745"><span class="linenos"> 745</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)</span>
+</span><span id="TemplateRegistry-746"><a href="#TemplateRegistry-746"><span class="linenos"> 746</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-747"><a href="#TemplateRegistry-747"><span class="linenos"> 747</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-748"><a href="#TemplateRegistry-748"><span class="linenos"> 748</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 6&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-749"><a href="#TemplateRegistry-749"><span class="linenos"> 749</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-750"><a href="#TemplateRegistry-750"><span class="linenos"> 750</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-751"><a href="#TemplateRegistry-751"><span class="linenos"> 751</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-752"><a href="#TemplateRegistry-752"><span class="linenos"> 752</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-753"><a href="#TemplateRegistry-753"><span class="linenos"> 753</span></a>
+</span><span id="TemplateRegistry-754"><a href="#TemplateRegistry-754"><span class="linenos"> 754</span></a><span class="sd">    Clients can be deregistered again (the result is False if the registry</span>
+</span><span id="TemplateRegistry-755"><a href="#TemplateRegistry-755"><span class="linenos"> 755</span></a><span class="sd">    is empty after the deletion):</span>
+</span><span id="TemplateRegistry-756"><a href="#TemplateRegistry-756"><span class="linenos"> 756</span></a><span class="sd">    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 7&#39;)</span>
+</span><span id="TemplateRegistry-757"><a href="#TemplateRegistry-757"><span class="linenos"> 757</span></a><span class="sd">    &gt;&gt;&gt; r.delete(&#39;C 7&#39;)</span>
+</span><span id="TemplateRegistry-758"><a href="#TemplateRegistry-758"><span class="linenos"> 758</span></a><span class="sd">    True</span>
+</span><span id="TemplateRegistry-759"><a href="#TemplateRegistry-759"><span class="linenos"> 759</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-760"><a href="#TemplateRegistry-760"><span class="linenos"> 760</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-761"><a href="#TemplateRegistry-761"><span class="linenos"> 761</span></a><span class="sd">    ...     print(f&quot;{m}: {r.check(&#39;C 7&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-762"><a href="#TemplateRegistry-762"><span class="linenos"> 762</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-763"><a href="#TemplateRegistry-763"><span class="linenos"> 763</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-764"><a href="#TemplateRegistry-764"><span class="linenos"> 764</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-765"><a href="#TemplateRegistry-765"><span class="linenos"> 765</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-766"><a href="#TemplateRegistry-766"><span class="linenos"> 766</span></a>
+</span><span id="TemplateRegistry-767"><a href="#TemplateRegistry-767"><span class="linenos"> 767</span></a><span class="sd">    The get function returns all clients with registered templates matching</span>
+</span><span id="TemplateRegistry-768"><a href="#TemplateRegistry-768"><span class="linenos"> 768</span></a><span class="sd">    a given message:</span>
+</span><span id="TemplateRegistry-769"><a href="#TemplateRegistry-769"><span class="linenos"> 769</span></a><span class="sd">    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-770"><a href="#TemplateRegistry-770"><span class="linenos"> 770</span></a><span class="sd">    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-771"><a href="#TemplateRegistry-771"><span class="linenos"> 771</span></a><span class="sd">    ...     print(f&quot;{m}: {r.get(m)}&quot;)</span>
+</span><span id="TemplateRegistry-772"><a href="#TemplateRegistry-772"><span class="linenos"> 772</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;]</span>
+</span><span id="TemplateRegistry-773"><a href="#TemplateRegistry-773"><span class="linenos"> 773</span></a><span class="sd">    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;, &#39;C 4&#39;]</span>
+</span><span id="TemplateRegistry-774"><a href="#TemplateRegistry-774"><span class="linenos"> 774</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 2&#39;, &#39;C 6&#39;]</span>
+</span><span id="TemplateRegistry-775"><a href="#TemplateRegistry-775"><span class="linenos"> 775</span></a><span class="sd">    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 3&#39;, &#39;C 4&#39;]</span>
+</span><span id="TemplateRegistry-776"><a href="#TemplateRegistry-776"><span class="linenos"> 776</span></a>
+</span><span id="TemplateRegistry-777"><a href="#TemplateRegistry-777"><span class="linenos"> 777</span></a><span class="sd">    The get_templates function returns all templates for a given client:</span>
+</span><span id="TemplateRegistry-778"><a href="#TemplateRegistry-778"><span class="linenos"> 778</span></a><span class="sd">    &gt;&gt;&gt; for c in [&#39;C 1&#39;, &#39;C 2&#39;, &#39;C 3&#39;, &#39;C 4&#39;, &#39;C 5&#39;, &#39;C 6&#39;]:</span>
+</span><span id="TemplateRegistry-779"><a href="#TemplateRegistry-779"><span class="linenos"> 779</span></a><span class="sd">    ...     print(f&quot;{c}: {r.get_templates(c)}&quot;)</span>
+</span><span id="TemplateRegistry-780"><a href="#TemplateRegistry-780"><span class="linenos"> 780</span></a><span class="sd">    C 1: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="TemplateRegistry-781"><a href="#TemplateRegistry-781"><span class="linenos"> 781</span></a><span class="sd">    C 2: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+</span><span id="TemplateRegistry-782"><a href="#TemplateRegistry-782"><span class="linenos"> 782</span></a><span class="sd">    C 3: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+</span><span id="TemplateRegistry-783"><a href="#TemplateRegistry-783"><span class="linenos"> 783</span></a><span class="sd">    C 4: [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+</span><span id="TemplateRegistry-784"><a href="#TemplateRegistry-784"><span class="linenos"> 784</span></a><span class="sd">    C 5: [{}]</span>
+</span><span id="TemplateRegistry-785"><a href="#TemplateRegistry-785"><span class="linenos"> 785</span></a><span class="sd">    C 6: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="TemplateRegistry-786"><a href="#TemplateRegistry-786"><span class="linenos"> 786</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-787"><a href="#TemplateRegistry-787"><span class="linenos"> 787</span></a>
+</span><span id="TemplateRegistry-788"><a href="#TemplateRegistry-788"><span class="linenos"> 788</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="TemplateRegistry-789"><a href="#TemplateRegistry-789"><span class="linenos"> 789</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise an empty registry.</span>
+</span><span id="TemplateRegistry-790"><a href="#TemplateRegistry-790"><span class="linenos"> 790</span></a>
+</span><span id="TemplateRegistry-791"><a href="#TemplateRegistry-791"><span class="linenos"> 791</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-792"><a href="#TemplateRegistry-792"><span class="linenos"> 792</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-793"><a href="#TemplateRegistry-793"><span class="linenos"> 793</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry-794"><a href="#TemplateRegistry-794"><span class="linenos"> 794</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-795"><a href="#TemplateRegistry-795"><span class="linenos"> 795</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-796"><a href="#TemplateRegistry-796"><span class="linenos"> 796</span></a>        <span class="c1"># First key is the message key, second key is the constant string</span>
+</span><span id="TemplateRegistry-797"><a href="#TemplateRegistry-797"><span class="linenos"> 797</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-798"><a href="#TemplateRegistry-798"><span class="linenos"> 798</span></a>        <span class="c1"># First key is the message key, second key is the JSON schema string</span>
+</span><span id="TemplateRegistry-799"><a href="#TemplateRegistry-799"><span class="linenos"> 799</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-800"><a href="#TemplateRegistry-800"><span class="linenos"> 800</span></a>
+</span><span id="TemplateRegistry-801"><a href="#TemplateRegistry-801"><span class="linenos"> 801</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">insert</span><span class="p">(</span>
+</span><span id="TemplateRegistry-802"><a href="#TemplateRegistry-802"><span class="linenos"> 802</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="TemplateRegistry-803"><a href="#TemplateRegistry-803"><span class="linenos"> 803</span></a>        <span class="n">template</span><span class="p">:</span> <span class="n">MessageTemplate</span><span class="p">,</span>
+</span><span id="TemplateRegistry-804"><a href="#TemplateRegistry-804"><span class="linenos"> 804</span></a>        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="TemplateRegistry-805"><a href="#TemplateRegistry-805"><span class="linenos"> 805</span></a>        <span class="n">callback</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="TemplateRegistry-806"><a href="#TemplateRegistry-806"><span class="linenos"> 806</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="TemplateRegistry-807"><a href="#TemplateRegistry-807"><span class="linenos"> 807</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register a client for a template.</span>
+</span><span id="TemplateRegistry-808"><a href="#TemplateRegistry-808"><span class="linenos"> 808</span></a>
+</span><span id="TemplateRegistry-809"><a href="#TemplateRegistry-809"><span class="linenos"> 809</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-810"><a href="#TemplateRegistry-810"><span class="linenos"> 810</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="TemplateRegistry-811"><a href="#TemplateRegistry-811"><span class="linenos"> 811</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="TemplateRegistry-812"><a href="#TemplateRegistry-812"><span class="linenos"> 812</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry-813"><a href="#TemplateRegistry-813"><span class="linenos"> 813</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry-814"><a href="#TemplateRegistry-814"><span class="linenos"> 814</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="TemplateRegistry-815"><a href="#TemplateRegistry-815"><span class="linenos"> 815</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-816"><a href="#TemplateRegistry-816"><span class="linenos"> 816</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="TemplateRegistry-817"><a href="#TemplateRegistry-817"><span class="linenos"> 817</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry-818"><a href="#TemplateRegistry-818"><span class="linenos"> 818</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
+</span><span id="TemplateRegistry-819"><a href="#TemplateRegistry-819"><span class="linenos"> 819</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">template</span><span class="p">:</span>
+</span><span id="TemplateRegistry-820"><a href="#TemplateRegistry-820"><span class="linenos"> 820</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry-821"><a href="#TemplateRegistry-821"><span class="linenos"> 821</span></a>            <span class="k">if</span> <span class="n">callback</span><span class="p">:</span>
+</span><span id="TemplateRegistry-822"><a href="#TemplateRegistry-822"><span class="linenos"> 822</span></a>                <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="TemplateRegistry-823"><a href="#TemplateRegistry-823"><span class="linenos"> 823</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry-824"><a href="#TemplateRegistry-824"><span class="linenos"> 824</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry-825"><a href="#TemplateRegistry-825"><span class="linenos"> 825</span></a>        <span class="k">else</span><span class="p">:</span>
+</span><span id="TemplateRegistry-826"><a href="#TemplateRegistry-826"><span class="linenos"> 826</span></a>            <span class="n">key</span><span class="p">,</span> <span class="n">schema</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">items</span><span class="p">()))</span>
+</span><span id="TemplateRegistry-827"><a href="#TemplateRegistry-827"><span class="linenos"> 827</span></a>            <span class="n">reduced_template</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="TemplateRegistry-828"><a href="#TemplateRegistry-828"><span class="linenos"> 828</span></a>                <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">template</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">template</span> <span class="k">if</span> <span class="n">k</span> <span class="o">!=</span> <span class="n">key</span><span class="p">}</span>
+</span><span id="TemplateRegistry-829"><a href="#TemplateRegistry-829"><span class="linenos"> 829</span></a>            <span class="p">)</span>
+</span><span id="TemplateRegistry-830"><a href="#TemplateRegistry-830"><span class="linenos"> 830</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry-831"><a href="#TemplateRegistry-831"><span class="linenos"> 831</span></a>                <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span>
+</span><span id="TemplateRegistry-832"><a href="#TemplateRegistry-832"><span class="linenos"> 832</span></a>                <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
+</span><span id="TemplateRegistry-833"><a href="#TemplateRegistry-833"><span class="linenos"> 833</span></a>                <span class="ow">and</span> <span class="s2">&quot;const&quot;</span> <span class="ow">in</span> <span class="n">schema</span>
+</span><span id="TemplateRegistry-834"><a href="#TemplateRegistry-834"><span class="linenos"> 834</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">[</span><span class="s2">&quot;const&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-835"><a href="#TemplateRegistry-835"><span class="linenos"> 835</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry-836"><a href="#TemplateRegistry-836"><span class="linenos"> 836</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">schema</span><span class="p">[</span><span class="s2">&quot;const&quot;</span><span class="p">]</span>
+</span><span id="TemplateRegistry-837"><a href="#TemplateRegistry-837"><span class="linenos"> 837</span></a>                <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry-838"><a href="#TemplateRegistry-838"><span class="linenos"> 838</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-839"><a href="#TemplateRegistry-839"><span class="linenos"> 839</span></a>                <span class="k">if</span> <span class="n">value</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-840"><a href="#TemplateRegistry-840"><span class="linenos"> 840</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="TemplateRegistry-841"><a href="#TemplateRegistry-841"><span class="linenos"> 841</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">reduced_template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry-842"><a href="#TemplateRegistry-842"><span class="linenos"> 842</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="TemplateRegistry-843"><a href="#TemplateRegistry-843"><span class="linenos"> 843</span></a>                <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="TemplateRegistry-844"><a href="#TemplateRegistry-844"><span class="linenos"> 844</span></a>                <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry-845"><a href="#TemplateRegistry-845"><span class="linenos"> 845</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-846"><a href="#TemplateRegistry-846"><span class="linenos"> 846</span></a>                <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-847"><a href="#TemplateRegistry-847"><span class="linenos"> 847</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="TemplateRegistry-848"><a href="#TemplateRegistry-848"><span class="linenos"> 848</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span>
+</span><span id="TemplateRegistry-849"><a href="#TemplateRegistry-849"><span class="linenos"> 849</span></a>                    <span class="n">reduced_template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span>
+</span><span id="TemplateRegistry-850"><a href="#TemplateRegistry-850"><span class="linenos"> 850</span></a>                <span class="p">)</span>
+</span><span id="TemplateRegistry-851"><a href="#TemplateRegistry-851"><span class="linenos"> 851</span></a>
+</span><span id="TemplateRegistry-852"><a href="#TemplateRegistry-852"><span class="linenos"> 852</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">delete</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="TemplateRegistry-853"><a href="#TemplateRegistry-853"><span class="linenos"> 853</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Unregister a client from all templates.</span>
+</span><span id="TemplateRegistry-854"><a href="#TemplateRegistry-854"><span class="linenos"> 854</span></a>
+</span><span id="TemplateRegistry-855"><a href="#TemplateRegistry-855"><span class="linenos"> 855</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-856"><a href="#TemplateRegistry-856"><span class="linenos"> 856</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="TemplateRegistry-857"><a href="#TemplateRegistry-857"><span class="linenos"> 857</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="TemplateRegistry-858"><a href="#TemplateRegistry-858"><span class="linenos"> 858</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry-859"><a href="#TemplateRegistry-859"><span class="linenos"> 859</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry-860"><a href="#TemplateRegistry-860"><span class="linenos"> 860</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="TemplateRegistry-861"><a href="#TemplateRegistry-861"><span class="linenos"> 861</span></a><span class="sd">        &gt;&gt;&gt; r.delete(&#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry-862"><a href="#TemplateRegistry-862"><span class="linenos"> 862</span></a><span class="sd">        True</span>
+</span><span id="TemplateRegistry-863"><a href="#TemplateRegistry-863"><span class="linenos"> 863</span></a><span class="sd">        &gt;&gt;&gt; r.delete(&#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry-864"><a href="#TemplateRegistry-864"><span class="linenos"> 864</span></a><span class="sd">        True</span>
+</span><span id="TemplateRegistry-865"><a href="#TemplateRegistry-865"><span class="linenos"> 865</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-866"><a href="#TemplateRegistry-866"><span class="linenos"> 866</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="TemplateRegistry-867"><a href="#TemplateRegistry-867"><span class="linenos"> 867</span></a>            <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry-868"><a href="#TemplateRegistry-868"><span class="linenos"> 868</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="o">=</span> <span class="p">[</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="k">if</span> <span class="n">c</span> <span class="o">!=</span> <span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry-869"><a href="#TemplateRegistry-869"><span class="linenos"> 869</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="TemplateRegistry-870"><a href="#TemplateRegistry-870"><span class="linenos"> 870</span></a>            <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry-871"><a href="#TemplateRegistry-871"><span class="linenos"> 871</span></a>        <span class="n">new_constants</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-872"><a href="#TemplateRegistry-872"><span class="linenos"> 872</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry-873"><a href="#TemplateRegistry-873"><span class="linenos"> 873</span></a>            <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-874"><a href="#TemplateRegistry-874"><span class="linenos"> 874</span></a>            <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-875"><a href="#TemplateRegistry-875"><span class="linenos"> 875</span></a>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
+</span><span id="TemplateRegistry-876"><a href="#TemplateRegistry-876"><span class="linenos"> 876</span></a>                    <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry-877"><a href="#TemplateRegistry-877"><span class="linenos"> 877</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-878"><a href="#TemplateRegistry-878"><span class="linenos"> 878</span></a>                <span class="k">del</span> <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-879"><a href="#TemplateRegistry-879"><span class="linenos"> 879</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span> <span class="o">=</span> <span class="n">new_constants</span>
+</span><span id="TemplateRegistry-880"><a href="#TemplateRegistry-880"><span class="linenos"> 880</span></a>        <span class="n">new_schemas</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-881"><a href="#TemplateRegistry-881"><span class="linenos"> 881</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry-882"><a href="#TemplateRegistry-882"><span class="linenos"> 882</span></a>            <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry-883"><a href="#TemplateRegistry-883"><span class="linenos"> 883</span></a>            <span class="k">for</span> <span class="n">schema</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-884"><a href="#TemplateRegistry-884"><span class="linenos"> 884</span></a>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
+</span><span id="TemplateRegistry-885"><a href="#TemplateRegistry-885"><span class="linenos"> 885</span></a>                    <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span>
+</span><span id="TemplateRegistry-886"><a href="#TemplateRegistry-886"><span class="linenos"> 886</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-887"><a href="#TemplateRegistry-887"><span class="linenos"> 887</span></a>                <span class="k">del</span> <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-888"><a href="#TemplateRegistry-888"><span class="linenos"> 888</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span> <span class="o">=</span> <span class="n">new_schemas</span>
+</span><span id="TemplateRegistry-889"><a href="#TemplateRegistry-889"><span class="linenos"> 889</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry-890"><a href="#TemplateRegistry-890"><span class="linenos"> 890</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry-891"><a href="#TemplateRegistry-891"><span class="linenos"> 891</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="TemplateRegistry-892"><a href="#TemplateRegistry-892"><span class="linenos"> 892</span></a>
+</span><span id="TemplateRegistry-893"><a href="#TemplateRegistry-893"><span class="linenos"> 893</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="TemplateRegistry-894"><a href="#TemplateRegistry-894"><span class="linenos"> 894</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get if a client has a registered template matching a message.</span>
+</span><span id="TemplateRegistry-895"><a href="#TemplateRegistry-895"><span class="linenos"> 895</span></a>
+</span><span id="TemplateRegistry-896"><a href="#TemplateRegistry-896"><span class="linenos"> 896</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-897"><a href="#TemplateRegistry-897"><span class="linenos"> 897</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry-898"><a href="#TemplateRegistry-898"><span class="linenos"> 898</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-899"><a href="#TemplateRegistry-899"><span class="linenos"> 899</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-900"><a href="#TemplateRegistry-900"><span class="linenos"> 900</span></a><span class="sd">        ...     print(f&quot;{m}: {r.check(&#39;Client 1&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-901"><a href="#TemplateRegistry-901"><span class="linenos"> 901</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry-902"><a href="#TemplateRegistry-902"><span class="linenos"> 902</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-903"><a href="#TemplateRegistry-903"><span class="linenos"> 903</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-904"><a href="#TemplateRegistry-904"><span class="linenos"> 904</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry-905"><a href="#TemplateRegistry-905"><span class="linenos"> 905</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry-906"><a href="#TemplateRegistry-906"><span class="linenos"> 906</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-907"><a href="#TemplateRegistry-907"><span class="linenos"> 907</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-908"><a href="#TemplateRegistry-908"><span class="linenos"> 908</span></a><span class="sd">        ...     print(f&quot;{m}: {r.check(&#39;Client 2&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry-909"><a href="#TemplateRegistry-909"><span class="linenos"> 909</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-910"><a href="#TemplateRegistry-910"><span class="linenos"> 910</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-911"><a href="#TemplateRegistry-911"><span class="linenos"> 911</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry-912"><a href="#TemplateRegistry-912"><span class="linenos"> 912</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry-913"><a href="#TemplateRegistry-913"><span class="linenos"> 913</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-914"><a href="#TemplateRegistry-914"><span class="linenos"> 914</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span>
+</span><span id="TemplateRegistry-915"><a href="#TemplateRegistry-915"><span class="linenos"> 915</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry-916"><a href="#TemplateRegistry-916"><span class="linenos"> 916</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry-917"><a href="#TemplateRegistry-917"><span class="linenos"> 917</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry-918"><a href="#TemplateRegistry-918"><span class="linenos"> 918</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="TemplateRegistry-919"><a href="#TemplateRegistry-919"><span class="linenos"> 919</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-920"><a href="#TemplateRegistry-920"><span class="linenos"> 920</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-921"><a href="#TemplateRegistry-921"><span class="linenos"> 921</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry-922"><a href="#TemplateRegistry-922"><span class="linenos"> 922</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-923"><a href="#TemplateRegistry-923"><span class="linenos"> 923</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-924"><a href="#TemplateRegistry-924"><span class="linenos"> 924</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry-925"><a href="#TemplateRegistry-925"><span class="linenos"> 925</span></a>                <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry-926"><a href="#TemplateRegistry-926"><span class="linenos"> 926</span></a>                    <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry-927"><a href="#TemplateRegistry-927"><span class="linenos"> 927</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry-928"><a href="#TemplateRegistry-928"><span class="linenos"> 928</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="TemplateRegistry-929"><a href="#TemplateRegistry-929"><span class="linenos"> 929</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-930"><a href="#TemplateRegistry-930"><span class="linenos"> 930</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="TemplateRegistry-931"><a href="#TemplateRegistry-931"><span class="linenos"> 931</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="TemplateRegistry-932"><a href="#TemplateRegistry-932"><span class="linenos"> 932</span></a>                        <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry-933"><a href="#TemplateRegistry-933"><span class="linenos"> 933</span></a>                            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry-934"><a href="#TemplateRegistry-934"><span class="linenos"> 934</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span><span id="TemplateRegistry-935"><a href="#TemplateRegistry-935"><span class="linenos"> 935</span></a>
+</span><span id="TemplateRegistry-936"><a href="#TemplateRegistry-936"><span class="linenos"> 936</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-937"><a href="#TemplateRegistry-937"><span class="linenos"> 937</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all clients registered for templates matching a message.</span>
+</span><span id="TemplateRegistry-938"><a href="#TemplateRegistry-938"><span class="linenos"> 938</span></a>
+</span><span id="TemplateRegistry-939"><a href="#TemplateRegistry-939"><span class="linenos"> 939</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-940"><a href="#TemplateRegistry-940"><span class="linenos"> 940</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry-941"><a href="#TemplateRegistry-941"><span class="linenos"> 941</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry-942"><a href="#TemplateRegistry-942"><span class="linenos"> 942</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry-943"><a href="#TemplateRegistry-943"><span class="linenos"> 943</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry-944"><a href="#TemplateRegistry-944"><span class="linenos"> 944</span></a><span class="sd">        ...     print(f&quot;{m}: {r.get(m)}&quot;)</span>
+</span><span id="TemplateRegistry-945"><a href="#TemplateRegistry-945"><span class="linenos"> 945</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]</span>
+</span><span id="TemplateRegistry-946"><a href="#TemplateRegistry-946"><span class="linenos"> 946</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;Client 1&#39;, &#39;Client 2&#39;]</span>
+</span><span id="TemplateRegistry-947"><a href="#TemplateRegistry-947"><span class="linenos"> 947</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []</span>
+</span><span id="TemplateRegistry-948"><a href="#TemplateRegistry-948"><span class="linenos"> 948</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;Client 2&#39;]</span>
+</span><span id="TemplateRegistry-949"><a href="#TemplateRegistry-949"><span class="linenos"> 949</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-950"><a href="#TemplateRegistry-950"><span class="linenos"> 950</span></a>        <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry-951"><a href="#TemplateRegistry-951"><span class="linenos"> 951</span></a>        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span>
+</span><span id="TemplateRegistry-952"><a href="#TemplateRegistry-952"><span class="linenos"> 952</span></a>            <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry-953"><a href="#TemplateRegistry-953"><span class="linenos"> 953</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry-954"><a href="#TemplateRegistry-954"><span class="linenos"> 954</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry-955"><a href="#TemplateRegistry-955"><span class="linenos"> 955</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry-956"><a href="#TemplateRegistry-956"><span class="linenos"> 956</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="TemplateRegistry-957"><a href="#TemplateRegistry-957"><span class="linenos"> 957</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-958"><a href="#TemplateRegistry-958"><span class="linenos"> 958</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-959"><a href="#TemplateRegistry-959"><span class="linenos"> 959</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry-960"><a href="#TemplateRegistry-960"><span class="linenos"> 960</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-961"><a href="#TemplateRegistry-961"><span class="linenos"> 961</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-962"><a href="#TemplateRegistry-962"><span class="linenos"> 962</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry-963"><a href="#TemplateRegistry-963"><span class="linenos"> 963</span></a>                <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry-964"><a href="#TemplateRegistry-964"><span class="linenos"> 964</span></a>                    <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry-965"><a href="#TemplateRegistry-965"><span class="linenos"> 965</span></a>                        <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry-966"><a href="#TemplateRegistry-966"><span class="linenos"> 966</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry-967"><a href="#TemplateRegistry-967"><span class="linenos"> 967</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="TemplateRegistry-968"><a href="#TemplateRegistry-968"><span class="linenos"> 968</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-969"><a href="#TemplateRegistry-969"><span class="linenos"> 969</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="TemplateRegistry-970"><a href="#TemplateRegistry-970"><span class="linenos"> 970</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="TemplateRegistry-971"><a href="#TemplateRegistry-971"><span class="linenos"> 971</span></a>                        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry-972"><a href="#TemplateRegistry-972"><span class="linenos"> 972</span></a>                            <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry-973"><a href="#TemplateRegistry-973"><span class="linenos"> 973</span></a>                                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry-974"><a href="#TemplateRegistry-974"><span class="linenos"> 974</span></a>        <span class="k">return</span> <span class="n">result</span>
+</span><span id="TemplateRegistry-975"><a href="#TemplateRegistry-975"><span class="linenos"> 975</span></a>
+</span><span id="TemplateRegistry-976"><a href="#TemplateRegistry-976"><span class="linenos"> 976</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get_callbacks</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-977"><a href="#TemplateRegistry-977"><span class="linenos"> 977</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all callbacks registered for templates matching a message.&quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-978"><a href="#TemplateRegistry-978"><span class="linenos"> 978</span></a>        <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry-979"><a href="#TemplateRegistry-979"><span class="linenos"> 979</span></a>        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="TemplateRegistry-980"><a href="#TemplateRegistry-980"><span class="linenos"> 980</span></a>            <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-981"><a href="#TemplateRegistry-981"><span class="linenos"> 981</span></a>                <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry-982"><a href="#TemplateRegistry-982"><span class="linenos"> 982</span></a>                    <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry-983"><a href="#TemplateRegistry-983"><span class="linenos"> 983</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry-984"><a href="#TemplateRegistry-984"><span class="linenos"> 984</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry-985"><a href="#TemplateRegistry-985"><span class="linenos"> 985</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="TemplateRegistry-986"><a href="#TemplateRegistry-986"><span class="linenos"> 986</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-987"><a href="#TemplateRegistry-987"><span class="linenos"> 987</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-988"><a href="#TemplateRegistry-988"><span class="linenos"> 988</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry-989"><a href="#TemplateRegistry-989"><span class="linenos"> 989</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry-990"><a href="#TemplateRegistry-990"><span class="linenos"> 990</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry-991"><a href="#TemplateRegistry-991"><span class="linenos"> 991</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry-992"><a href="#TemplateRegistry-992"><span class="linenos"> 992</span></a>                <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry-993"><a href="#TemplateRegistry-993"><span class="linenos"> 993</span></a>                    <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry-994"><a href="#TemplateRegistry-994"><span class="linenos"> 994</span></a>                        <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry-995"><a href="#TemplateRegistry-995"><span class="linenos"> 995</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry-996"><a href="#TemplateRegistry-996"><span class="linenos"> 996</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="TemplateRegistry-997"><a href="#TemplateRegistry-997"><span class="linenos"> 997</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-998"><a href="#TemplateRegistry-998"><span class="linenos"> 998</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="TemplateRegistry-999"><a href="#TemplateRegistry-999"><span class="linenos"> 999</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="TemplateRegistry-1000"><a href="#TemplateRegistry-1000"><span class="linenos">1000</span></a>                        <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry-1001"><a href="#TemplateRegistry-1001"><span class="linenos">1001</span></a>                            <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry-1002"><a href="#TemplateRegistry-1002"><span class="linenos">1002</span></a>                                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry-1003"><a href="#TemplateRegistry-1003"><span class="linenos">1003</span></a>        <span class="k">return</span> <span class="n">result</span>
+</span><span id="TemplateRegistry-1004"><a href="#TemplateRegistry-1004"><span class="linenos">1004</span></a>
+</span><span id="TemplateRegistry-1005"><a href="#TemplateRegistry-1005"><span class="linenos">1005</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get_templates</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]:</span>
+</span><span id="TemplateRegistry-1006"><a href="#TemplateRegistry-1006"><span class="linenos">1006</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all templates for a client.</span>
+</span><span id="TemplateRegistry-1007"><a href="#TemplateRegistry-1007"><span class="linenos">1007</span></a>
+</span><span id="TemplateRegistry-1008"><a href="#TemplateRegistry-1008"><span class="linenos">1008</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry-1009"><a href="#TemplateRegistry-1009"><span class="linenos">1009</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry-1010"><a href="#TemplateRegistry-1010"><span class="linenos">1010</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry-1011"><a href="#TemplateRegistry-1011"><span class="linenos">1011</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="TemplateRegistry-1012"><a href="#TemplateRegistry-1012"><span class="linenos">1012</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},</span>
+</span><span id="TemplateRegistry-1013"><a href="#TemplateRegistry-1013"><span class="linenos">1013</span></a><span class="sd">        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry-1014"><a href="#TemplateRegistry-1014"><span class="linenos">1014</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry-1015"><a href="#TemplateRegistry-1015"><span class="linenos">1015</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+</span><span id="TemplateRegistry-1016"><a href="#TemplateRegistry-1016"><span class="linenos">1016</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},</span>
+</span><span id="TemplateRegistry-1017"><a href="#TemplateRegistry-1017"><span class="linenos">1017</span></a><span class="sd">        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 3&#39;)</span>
+</span><span id="TemplateRegistry-1018"><a href="#TemplateRegistry-1018"><span class="linenos">1018</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 3&#39;)</span>
+</span><span id="TemplateRegistry-1019"><a href="#TemplateRegistry-1019"><span class="linenos">1019</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+</span><span id="TemplateRegistry-1020"><a href="#TemplateRegistry-1020"><span class="linenos">1020</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;Client 4&#39;)</span>
+</span><span id="TemplateRegistry-1021"><a href="#TemplateRegistry-1021"><span class="linenos">1021</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 4&#39;)</span>
+</span><span id="TemplateRegistry-1022"><a href="#TemplateRegistry-1022"><span class="linenos">1022</span></a><span class="sd">        [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+</span><span id="TemplateRegistry-1023"><a href="#TemplateRegistry-1023"><span class="linenos">1023</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;Client 5&#39;)</span>
+</span><span id="TemplateRegistry-1024"><a href="#TemplateRegistry-1024"><span class="linenos">1024</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 5&#39;)</span>
+</span><span id="TemplateRegistry-1025"><a href="#TemplateRegistry-1025"><span class="linenos">1025</span></a><span class="sd">        [{}]</span>
+</span><span id="TemplateRegistry-1026"><a href="#TemplateRegistry-1026"><span class="linenos">1026</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)</span>
+</span><span id="TemplateRegistry-1027"><a href="#TemplateRegistry-1027"><span class="linenos">1027</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)</span>
+</span><span id="TemplateRegistry-1028"><a href="#TemplateRegistry-1028"><span class="linenos">1028</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 6&#39;)</span>
+</span><span id="TemplateRegistry-1029"><a href="#TemplateRegistry-1029"><span class="linenos">1029</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="TemplateRegistry-1030"><a href="#TemplateRegistry-1030"><span class="linenos">1030</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry-1031"><a href="#TemplateRegistry-1031"><span class="linenos">1031</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="TemplateRegistry-1032"><a href="#TemplateRegistry-1032"><span class="linenos">1032</span></a>            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry-1033"><a href="#TemplateRegistry-1033"><span class="linenos">1033</span></a>        <span class="k">return</span> <span class="p">[]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Manage a collection of message templates with registered clients.</p>
+
+<p>A new TemplateRegistry is created by:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</code></pre>
+</div>
+
+<p>Client names (strings) can be registered for message templates, which
+are mappings from keys to JSON schemas:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 1&#39;</span><span class="p">)</span>
+</code></pre>
+</div>
+
+<p>The check function checks if the templates registered for a client
+match a given message:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 1&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</code></pre>
+</div>
+
+<p>Clients can be registered for values validating against arbitrary JSON
+schemas, e.g. all values of a certain type:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 2&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 2&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 3&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 3&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</code></pre>
+</div>
+
+<p>The order of key-value pairs does not have to match the order in the
+messages and keys can be left out:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}},</span> <span class="s1">&#39;C 4&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 4&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</code></pre>
+</div>
+
+<p>A registration for an empty template matches all messages:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({},</span> <span class="s1">&#39;C 5&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 5&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</code></pre>
+</div>
+
+<p>A client can be registered for multiple templates:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 6&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 6&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 6&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</code></pre>
+</div>
+
+<p>Clients can be deregistered again (the result is False if the registry
+is empty after the deletion):</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 7&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s1">&#39;C 7&#39;</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;C 7&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</code></pre>
+</div>
+
+<p>The get function returns all clients with registered templates matching
+a given message:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;]</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;, &#39;C 4&#39;]</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 2&#39;, &#39;C 6&#39;]</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 3&#39;, &#39;C 4&#39;]</span>
+</code></pre>
+</div>
+
+<p>The get_templates function returns all templates for a given client:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;C 1&#39;</span><span class="p">,</span> <span class="s1">&#39;C 2&#39;</span><span class="p">,</span> <span class="s1">&#39;C 3&#39;</span><span class="p">,</span> <span class="s1">&#39;C 4&#39;</span><span class="p">,</span> <span class="s1">&#39;C 5&#39;</span><span class="p">,</span> <span class="s1">&#39;C 6&#39;</span><span class="p">]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">c</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">C 1: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+<span class="go">C 2: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+<span class="go">C 3: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+<span class="go">C 4: [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+<span class="go">C 5: [{}]</span>
+<span class="go">C 6: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="TemplateRegistry.__init__" class="classattr">
+                                        <input id="TemplateRegistry.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="name">TemplateRegistry</span><span class="signature pdoc-code condensed">()</span>
+
+                <label class="view-source-button" for="TemplateRegistry.__init__-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.__init__"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.__init__-788"><a href="#TemplateRegistry.__init__-788"><span class="linenos">788</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="TemplateRegistry.__init__-789"><a href="#TemplateRegistry.__init__-789"><span class="linenos">789</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise an empty registry.</span>
+</span><span id="TemplateRegistry.__init__-790"><a href="#TemplateRegistry.__init__-790"><span class="linenos">790</span></a>
+</span><span id="TemplateRegistry.__init__-791"><a href="#TemplateRegistry.__init__-791"><span class="linenos">791</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry.__init__-792"><a href="#TemplateRegistry.__init__-792"><span class="linenos">792</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.__init__-793"><a href="#TemplateRegistry.__init__-793"><span class="linenos">793</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry.__init__-794"><a href="#TemplateRegistry.__init__-794"><span class="linenos">794</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.__init__-795"><a href="#TemplateRegistry.__init__-795"><span class="linenos">795</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.__init__-796"><a href="#TemplateRegistry.__init__-796"><span class="linenos">796</span></a>        <span class="c1"># First key is the message key, second key is the constant string</span>
+</span><span id="TemplateRegistry.__init__-797"><a href="#TemplateRegistry.__init__-797"><span class="linenos">797</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.__init__-798"><a href="#TemplateRegistry.__init__-798"><span class="linenos">798</span></a>        <span class="c1"># First key is the message key, second key is the JSON schema string</span>
+</span><span id="TemplateRegistry.__init__-799"><a href="#TemplateRegistry.__init__-799"><span class="linenos">799</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Initialise an empty registry.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="TemplateRegistry.insert" class="classattr">
+                                        <input id="TemplateRegistry.insert-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">insert</span><span class="signature pdoc-code multiline">(<span class="param">      <span class="bp">self</span>,</span><span class="param">        <span class="n">template</span><span class="p">:</span> <span class="n"><a href="#MessageTemplate">MessageTemplate</a></span>,</span><span class="param">       <span class="n">client</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">   <span class="n">callback</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n"><a href="#Message">Message</a></span><span class="p">],</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="TemplateRegistry.insert-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.insert"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.insert-801"><a href="#TemplateRegistry.insert-801"><span class="linenos">801</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">insert</span><span class="p">(</span>
+</span><span id="TemplateRegistry.insert-802"><a href="#TemplateRegistry.insert-802"><span class="linenos">802</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="TemplateRegistry.insert-803"><a href="#TemplateRegistry.insert-803"><span class="linenos">803</span></a>        <span class="n">template</span><span class="p">:</span> <span class="n">MessageTemplate</span><span class="p">,</span>
+</span><span id="TemplateRegistry.insert-804"><a href="#TemplateRegistry.insert-804"><span class="linenos">804</span></a>        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="TemplateRegistry.insert-805"><a href="#TemplateRegistry.insert-805"><span class="linenos">805</span></a>        <span class="n">callback</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
+</span><span id="TemplateRegistry.insert-806"><a href="#TemplateRegistry.insert-806"><span class="linenos">806</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-807"><a href="#TemplateRegistry.insert-807"><span class="linenos">807</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register a client for a template.</span>
+</span><span id="TemplateRegistry.insert-808"><a href="#TemplateRegistry.insert-808"><span class="linenos">808</span></a>
+</span><span id="TemplateRegistry.insert-809"><a href="#TemplateRegistry.insert-809"><span class="linenos">809</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry.insert-810"><a href="#TemplateRegistry.insert-810"><span class="linenos">810</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="TemplateRegistry.insert-811"><a href="#TemplateRegistry.insert-811"><span class="linenos">811</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="TemplateRegistry.insert-812"><a href="#TemplateRegistry.insert-812"><span class="linenos">812</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry.insert-813"><a href="#TemplateRegistry.insert-813"><span class="linenos">813</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry.insert-814"><a href="#TemplateRegistry.insert-814"><span class="linenos">814</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="TemplateRegistry.insert-815"><a href="#TemplateRegistry.insert-815"><span class="linenos">815</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.insert-816"><a href="#TemplateRegistry.insert-816"><span class="linenos">816</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-817"><a href="#TemplateRegistry.insert-817"><span class="linenos">817</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry.insert-818"><a href="#TemplateRegistry.insert-818"><span class="linenos">818</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-819"><a href="#TemplateRegistry.insert-819"><span class="linenos">819</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">template</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-820"><a href="#TemplateRegistry.insert-820"><span class="linenos">820</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-821"><a href="#TemplateRegistry.insert-821"><span class="linenos">821</span></a>            <span class="k">if</span> <span class="n">callback</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-822"><a href="#TemplateRegistry.insert-822"><span class="linenos">822</span></a>                <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-823"><a href="#TemplateRegistry.insert-823"><span class="linenos">823</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry.insert-824"><a href="#TemplateRegistry.insert-824"><span class="linenos">824</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-825"><a href="#TemplateRegistry.insert-825"><span class="linenos">825</span></a>        <span class="k">else</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-826"><a href="#TemplateRegistry.insert-826"><span class="linenos">826</span></a>            <span class="n">key</span><span class="p">,</span> <span class="n">schema</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">items</span><span class="p">()))</span>
+</span><span id="TemplateRegistry.insert-827"><a href="#TemplateRegistry.insert-827"><span class="linenos">827</span></a>            <span class="n">reduced_template</span> <span class="o">=</span> <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="TemplateRegistry.insert-828"><a href="#TemplateRegistry.insert-828"><span class="linenos">828</span></a>                <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">template</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">template</span> <span class="k">if</span> <span class="n">k</span> <span class="o">!=</span> <span class="n">key</span><span class="p">}</span>
+</span><span id="TemplateRegistry.insert-829"><a href="#TemplateRegistry.insert-829"><span class="linenos">829</span></a>            <span class="p">)</span>
+</span><span id="TemplateRegistry.insert-830"><a href="#TemplateRegistry.insert-830"><span class="linenos">830</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry.insert-831"><a href="#TemplateRegistry.insert-831"><span class="linenos">831</span></a>                <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-832"><a href="#TemplateRegistry.insert-832"><span class="linenos">832</span></a>                <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
+</span><span id="TemplateRegistry.insert-833"><a href="#TemplateRegistry.insert-833"><span class="linenos">833</span></a>                <span class="ow">and</span> <span class="s2">&quot;const&quot;</span> <span class="ow">in</span> <span class="n">schema</span>
+</span><span id="TemplateRegistry.insert-834"><a href="#TemplateRegistry.insert-834"><span class="linenos">834</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">schema</span><span class="p">[</span><span class="s2">&quot;const&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-835"><a href="#TemplateRegistry.insert-835"><span class="linenos">835</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry.insert-836"><a href="#TemplateRegistry.insert-836"><span class="linenos">836</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">schema</span><span class="p">[</span><span class="s2">&quot;const&quot;</span><span class="p">]</span>
+</span><span id="TemplateRegistry.insert-837"><a href="#TemplateRegistry.insert-837"><span class="linenos">837</span></a>                <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-838"><a href="#TemplateRegistry.insert-838"><span class="linenos">838</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.insert-839"><a href="#TemplateRegistry.insert-839"><span class="linenos">839</span></a>                <span class="k">if</span> <span class="n">value</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.insert-840"><a href="#TemplateRegistry.insert-840"><span class="linenos">840</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="TemplateRegistry.insert-841"><a href="#TemplateRegistry.insert-841"><span class="linenos">841</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">reduced_template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-842"><a href="#TemplateRegistry.insert-842"><span class="linenos">842</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-843"><a href="#TemplateRegistry.insert-843"><span class="linenos">843</span></a>                <span class="n">schema_string</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">schema</span><span class="p">)</span>
+</span><span id="TemplateRegistry.insert-844"><a href="#TemplateRegistry.insert-844"><span class="linenos">844</span></a>                <span class="k">if</span> <span class="n">key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry.insert-845"><a href="#TemplateRegistry.insert-845"><span class="linenos">845</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.insert-846"><a href="#TemplateRegistry.insert-846"><span class="linenos">846</span></a>                <span class="k">if</span> <span class="n">schema_string</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.insert-847"><a href="#TemplateRegistry.insert-847"><span class="linenos">847</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="TemplateRegistry.insert-848"><a href="#TemplateRegistry.insert-848"><span class="linenos">848</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span>
+</span><span id="TemplateRegistry.insert-849"><a href="#TemplateRegistry.insert-849"><span class="linenos">849</span></a>                    <span class="n">reduced_template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span>
+</span><span id="TemplateRegistry.insert-850"><a href="#TemplateRegistry.insert-850"><span class="linenos">850</span></a>                <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register a client for a template.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 1&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 2&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 3&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 4&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({},</span> <span class="s1">&#39;C 5&#39;</span><span class="p">)</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="TemplateRegistry.delete" class="classattr">
+                                        <input id="TemplateRegistry.delete-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">delete</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">client</span><span class="p">:</span> <span class="nb">str</span></span><span class="return-annotation">) -> <span class="nb">bool</span>:</span></span>
+
+                <label class="view-source-button" for="TemplateRegistry.delete-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.delete"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.delete-852"><a href="#TemplateRegistry.delete-852"><span class="linenos">852</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">delete</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="TemplateRegistry.delete-853"><a href="#TemplateRegistry.delete-853"><span class="linenos">853</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Unregister a client from all templates.</span>
+</span><span id="TemplateRegistry.delete-854"><a href="#TemplateRegistry.delete-854"><span class="linenos">854</span></a>
+</span><span id="TemplateRegistry.delete-855"><a href="#TemplateRegistry.delete-855"><span class="linenos">855</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry.delete-856"><a href="#TemplateRegistry.delete-856"><span class="linenos">856</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 1&#39;)</span>
+</span><span id="TemplateRegistry.delete-857"><a href="#TemplateRegistry.delete-857"><span class="linenos">857</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)</span>
+</span><span id="TemplateRegistry.delete-858"><a href="#TemplateRegistry.delete-858"><span class="linenos">858</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry.delete-859"><a href="#TemplateRegistry.delete-859"><span class="linenos">859</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;type&#39;: &#39;integer&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry.delete-860"><a href="#TemplateRegistry.delete-860"><span class="linenos">860</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)</span>
+</span><span id="TemplateRegistry.delete-861"><a href="#TemplateRegistry.delete-861"><span class="linenos">861</span></a><span class="sd">        &gt;&gt;&gt; r.delete(&#39;C 3&#39;)</span>
+</span><span id="TemplateRegistry.delete-862"><a href="#TemplateRegistry.delete-862"><span class="linenos">862</span></a><span class="sd">        True</span>
+</span><span id="TemplateRegistry.delete-863"><a href="#TemplateRegistry.delete-863"><span class="linenos">863</span></a><span class="sd">        &gt;&gt;&gt; r.delete(&#39;C 4&#39;)</span>
+</span><span id="TemplateRegistry.delete-864"><a href="#TemplateRegistry.delete-864"><span class="linenos">864</span></a><span class="sd">        True</span>
+</span><span id="TemplateRegistry.delete-865"><a href="#TemplateRegistry.delete-865"><span class="linenos">865</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.delete-866"><a href="#TemplateRegistry.delete-866"><span class="linenos">866</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="TemplateRegistry.delete-867"><a href="#TemplateRegistry.delete-867"><span class="linenos">867</span></a>            <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-868"><a href="#TemplateRegistry.delete-868"><span class="linenos">868</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="o">=</span> <span class="p">[</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="k">if</span> <span class="n">c</span> <span class="o">!=</span> <span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-869"><a href="#TemplateRegistry.delete-869"><span class="linenos">869</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="TemplateRegistry.delete-870"><a href="#TemplateRegistry.delete-870"><span class="linenos">870</span></a>            <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-871"><a href="#TemplateRegistry.delete-871"><span class="linenos">871</span></a>        <span class="n">new_constants</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.delete-872"><a href="#TemplateRegistry.delete-872"><span class="linenos">872</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry.delete-873"><a href="#TemplateRegistry.delete-873"><span class="linenos">873</span></a>            <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.delete-874"><a href="#TemplateRegistry.delete-874"><span class="linenos">874</span></a>            <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.delete-875"><a href="#TemplateRegistry.delete-875"><span class="linenos">875</span></a>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
+</span><span id="TemplateRegistry.delete-876"><a href="#TemplateRegistry.delete-876"><span class="linenos">876</span></a>                    <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-877"><a href="#TemplateRegistry.delete-877"><span class="linenos">877</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.delete-878"><a href="#TemplateRegistry.delete-878"><span class="linenos">878</span></a>                <span class="k">del</span> <span class="n">new_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-879"><a href="#TemplateRegistry.delete-879"><span class="linenos">879</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span> <span class="o">=</span> <span class="n">new_constants</span>
+</span><span id="TemplateRegistry.delete-880"><a href="#TemplateRegistry.delete-880"><span class="linenos">880</span></a>        <span class="n">new_schemas</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">TemplateRegistry</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.delete-881"><a href="#TemplateRegistry.delete-881"><span class="linenos">881</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry.delete-882"><a href="#TemplateRegistry.delete-882"><span class="linenos">882</span></a>            <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="TemplateRegistry.delete-883"><a href="#TemplateRegistry.delete-883"><span class="linenos">883</span></a>            <span class="k">for</span> <span class="n">schema</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.delete-884"><a href="#TemplateRegistry.delete-884"><span class="linenos">884</span></a>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">):</span>
+</span><span id="TemplateRegistry.delete-885"><a href="#TemplateRegistry.delete-885"><span class="linenos">885</span></a>                    <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-886"><a href="#TemplateRegistry.delete-886"><span class="linenos">886</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.delete-887"><a href="#TemplateRegistry.delete-887"><span class="linenos">887</span></a>                <span class="k">del</span> <span class="n">new_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.delete-888"><a href="#TemplateRegistry.delete-888"><span class="linenos">888</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span> <span class="o">=</span> <span class="n">new_schemas</span>
+</span><span id="TemplateRegistry.delete-889"><a href="#TemplateRegistry.delete-889"><span class="linenos">889</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry.delete-890"><a href="#TemplateRegistry.delete-890"><span class="linenos">890</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry.delete-891"><a href="#TemplateRegistry.delete-891"><span class="linenos">891</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Unregister a client from all templates.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 1&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 2&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 3&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">},</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">}},</span> <span class="s1">&#39;C 4&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({},</span> <span class="s1">&#39;C 5&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s1">&#39;C 3&#39;</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s1">&#39;C 4&#39;</span><span class="p">)</span>
+<span class="go">True</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="TemplateRegistry.check" class="classattr">
+                                        <input id="TemplateRegistry.check-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">check</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">client</span><span class="p">:</span> <span class="nb">str</span>, </span><span class="param"><span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="nb">bool</span>:</span></span>
+
+                <label class="view-source-button" for="TemplateRegistry.check-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.check"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.check-893"><a href="#TemplateRegistry.check-893"><span class="linenos">893</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+</span><span id="TemplateRegistry.check-894"><a href="#TemplateRegistry.check-894"><span class="linenos">894</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get if a client has a registered template matching a message.</span>
+</span><span id="TemplateRegistry.check-895"><a href="#TemplateRegistry.check-895"><span class="linenos">895</span></a>
+</span><span id="TemplateRegistry.check-896"><a href="#TemplateRegistry.check-896"><span class="linenos">896</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry.check-897"><a href="#TemplateRegistry.check-897"><span class="linenos">897</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry.check-898"><a href="#TemplateRegistry.check-898"><span class="linenos">898</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry.check-899"><a href="#TemplateRegistry.check-899"><span class="linenos">899</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry.check-900"><a href="#TemplateRegistry.check-900"><span class="linenos">900</span></a><span class="sd">        ...     print(f&quot;{m}: {r.check(&#39;Client 1&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry.check-901"><a href="#TemplateRegistry.check-901"><span class="linenos">901</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+</span><span id="TemplateRegistry.check-902"><a href="#TemplateRegistry.check-902"><span class="linenos">902</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry.check-903"><a href="#TemplateRegistry.check-903"><span class="linenos">903</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry.check-904"><a href="#TemplateRegistry.check-904"><span class="linenos">904</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+</span><span id="TemplateRegistry.check-905"><a href="#TemplateRegistry.check-905"><span class="linenos">905</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry.check-906"><a href="#TemplateRegistry.check-906"><span class="linenos">906</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry.check-907"><a href="#TemplateRegistry.check-907"><span class="linenos">907</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry.check-908"><a href="#TemplateRegistry.check-908"><span class="linenos">908</span></a><span class="sd">        ...     print(f&quot;{m}: {r.check(&#39;Client 2&#39;, m)}&quot;)</span>
+</span><span id="TemplateRegistry.check-909"><a href="#TemplateRegistry.check-909"><span class="linenos">909</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry.check-910"><a href="#TemplateRegistry.check-910"><span class="linenos">910</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry.check-911"><a href="#TemplateRegistry.check-911"><span class="linenos">911</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+</span><span id="TemplateRegistry.check-912"><a href="#TemplateRegistry.check-912"><span class="linenos">912</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</span><span id="TemplateRegistry.check-913"><a href="#TemplateRegistry.check-913"><span class="linenos">913</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.check-914"><a href="#TemplateRegistry.check-914"><span class="linenos">914</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span>
+</span><span id="TemplateRegistry.check-915"><a href="#TemplateRegistry.check-915"><span class="linenos">915</span></a>            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry.check-916"><a href="#TemplateRegistry.check-916"><span class="linenos">916</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry.check-917"><a href="#TemplateRegistry.check-917"><span class="linenos">917</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry.check-918"><a href="#TemplateRegistry.check-918"><span class="linenos">918</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="TemplateRegistry.check-919"><a href="#TemplateRegistry.check-919"><span class="linenos">919</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.check-920"><a href="#TemplateRegistry.check-920"><span class="linenos">920</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.check-921"><a href="#TemplateRegistry.check-921"><span class="linenos">921</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry.check-922"><a href="#TemplateRegistry.check-922"><span class="linenos">922</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.check-923"><a href="#TemplateRegistry.check-923"><span class="linenos">923</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.check-924"><a href="#TemplateRegistry.check-924"><span class="linenos">924</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry.check-925"><a href="#TemplateRegistry.check-925"><span class="linenos">925</span></a>                <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry.check-926"><a href="#TemplateRegistry.check-926"><span class="linenos">926</span></a>                    <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry.check-927"><a href="#TemplateRegistry.check-927"><span class="linenos">927</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry.check-928"><a href="#TemplateRegistry.check-928"><span class="linenos">928</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="TemplateRegistry.check-929"><a href="#TemplateRegistry.check-929"><span class="linenos">929</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.check-930"><a href="#TemplateRegistry.check-930"><span class="linenos">930</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="TemplateRegistry.check-931"><a href="#TemplateRegistry.check-931"><span class="linenos">931</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="TemplateRegistry.check-932"><a href="#TemplateRegistry.check-932"><span class="linenos">932</span></a>                        <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry.check-933"><a href="#TemplateRegistry.check-933"><span class="linenos">933</span></a>                            <span class="k">return</span> <span class="kc">True</span>
+</span><span id="TemplateRegistry.check-934"><a href="#TemplateRegistry.check-934"><span class="linenos">934</span></a>        <span class="k">return</span> <span class="kc">False</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Get if a client has a registered template matching a message.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="TemplateRegistry.get" class="classattr">
+                                        <input id="TemplateRegistry.get-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">get</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>:</span></span>
+
+                <label class="view-source-button" for="TemplateRegistry.get-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.get"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.get-936"><a href="#TemplateRegistry.get-936"><span class="linenos">936</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.get-937"><a href="#TemplateRegistry.get-937"><span class="linenos">937</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all clients registered for templates matching a message.</span>
+</span><span id="TemplateRegistry.get-938"><a href="#TemplateRegistry.get-938"><span class="linenos">938</span></a>
+</span><span id="TemplateRegistry.get-939"><a href="#TemplateRegistry.get-939"><span class="linenos">939</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry.get-940"><a href="#TemplateRegistry.get-940"><span class="linenos">940</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry.get-941"><a href="#TemplateRegistry.get-941"><span class="linenos">941</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry.get-942"><a href="#TemplateRegistry.get-942"><span class="linenos">942</span></a><span class="sd">        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},</span>
+</span><span id="TemplateRegistry.get-943"><a href="#TemplateRegistry.get-943"><span class="linenos">943</span></a><span class="sd">        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:</span>
+</span><span id="TemplateRegistry.get-944"><a href="#TemplateRegistry.get-944"><span class="linenos">944</span></a><span class="sd">        ...     print(f&quot;{m}: {r.get(m)}&quot;)</span>
+</span><span id="TemplateRegistry.get-945"><a href="#TemplateRegistry.get-945"><span class="linenos">945</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]</span>
+</span><span id="TemplateRegistry.get-946"><a href="#TemplateRegistry.get-946"><span class="linenos">946</span></a><span class="sd">        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;Client 1&#39;, &#39;Client 2&#39;]</span>
+</span><span id="TemplateRegistry.get-947"><a href="#TemplateRegistry.get-947"><span class="linenos">947</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []</span>
+</span><span id="TemplateRegistry.get-948"><a href="#TemplateRegistry.get-948"><span class="linenos">948</span></a><span class="sd">        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;Client 2&#39;]</span>
+</span><span id="TemplateRegistry.get-949"><a href="#TemplateRegistry.get-949"><span class="linenos">949</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.get-950"><a href="#TemplateRegistry.get-950"><span class="linenos">950</span></a>        <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry.get-951"><a href="#TemplateRegistry.get-951"><span class="linenos">951</span></a>        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_clients</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-952"><a href="#TemplateRegistry.get-952"><span class="linenos">952</span></a>            <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-953"><a href="#TemplateRegistry.get-953"><span class="linenos">953</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get-954"><a href="#TemplateRegistry.get-954"><span class="linenos">954</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-955"><a href="#TemplateRegistry.get-955"><span class="linenos">955</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry.get-956"><a href="#TemplateRegistry.get-956"><span class="linenos">956</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="TemplateRegistry.get-957"><a href="#TemplateRegistry.get-957"><span class="linenos">957</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get-958"><a href="#TemplateRegistry.get-958"><span class="linenos">958</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get-959"><a href="#TemplateRegistry.get-959"><span class="linenos">959</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry.get-960"><a href="#TemplateRegistry.get-960"><span class="linenos">960</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get-961"><a href="#TemplateRegistry.get-961"><span class="linenos">961</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get-962"><a href="#TemplateRegistry.get-962"><span class="linenos">962</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get-963"><a href="#TemplateRegistry.get-963"><span class="linenos">963</span></a>                <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry.get-964"><a href="#TemplateRegistry.get-964"><span class="linenos">964</span></a>                    <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-965"><a href="#TemplateRegistry.get-965"><span class="linenos">965</span></a>                        <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get-966"><a href="#TemplateRegistry.get-966"><span class="linenos">966</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-967"><a href="#TemplateRegistry.get-967"><span class="linenos">967</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-968"><a href="#TemplateRegistry.get-968"><span class="linenos">968</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.get-969"><a href="#TemplateRegistry.get-969"><span class="linenos">969</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="TemplateRegistry.get-970"><a href="#TemplateRegistry.get-970"><span class="linenos">970</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get-971"><a href="#TemplateRegistry.get-971"><span class="linenos">971</span></a>                        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry.get-972"><a href="#TemplateRegistry.get-972"><span class="linenos">972</span></a>                            <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get-973"><a href="#TemplateRegistry.get-973"><span class="linenos">973</span></a>                                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get-974"><a href="#TemplateRegistry.get-974"><span class="linenos">974</span></a>        <span class="k">return</span> <span class="n">result</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Get all clients registered for templates matching a message.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="p">[{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">},</span> <span class="p">{</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">,</span> <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">m</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]</span>
+<span class="go">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;Client 1&#39;, &#39;Client 2&#39;]</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []</span>
+<span class="go">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;Client 2&#39;]</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="TemplateRegistry.get_callbacks" class="classattr">
+                                        <input id="TemplateRegistry.get_callbacks-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">get_callbacks</span><span class="signature pdoc-code multiline">(<span class="param">       <span class="bp">self</span>,</span><span class="param">        <span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="n">List</span><span class="p">[</span><span class="n">Callable</span><span class="p">[[</span><span class="n"><a href="#Message">Message</a></span><span class="p">],</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]]]</span>:</span></span>
+
+                <label class="view-source-button" for="TemplateRegistry.get_callbacks-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.get_callbacks"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.get_callbacks-976"><a href="#TemplateRegistry.get_callbacks-976"><span class="linenos"> 976</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get_callbacks</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageCallback</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.get_callbacks-977"><a href="#TemplateRegistry.get_callbacks-977"><span class="linenos"> 977</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all callbacks registered for templates matching a message.&quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.get_callbacks-978"><a href="#TemplateRegistry.get_callbacks-978"><span class="linenos"> 978</span></a>        <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="TemplateRegistry.get_callbacks-979"><a href="#TemplateRegistry.get_callbacks-979"><span class="linenos"> 979</span></a>        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-980"><a href="#TemplateRegistry.get_callbacks-980"><span class="linenos"> 980</span></a>            <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_callbacks</span><span class="p">[</span><span class="n">client</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.get_callbacks-981"><a href="#TemplateRegistry.get_callbacks-981"><span class="linenos"> 981</span></a>                <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-982"><a href="#TemplateRegistry.get_callbacks-982"><span class="linenos"> 982</span></a>                    <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get_callbacks-983"><a href="#TemplateRegistry.get_callbacks-983"><span class="linenos"> 983</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-984"><a href="#TemplateRegistry.get_callbacks-984"><span class="linenos"> 984</span></a>            <span class="k">if</span> <span class="p">(</span>
+</span><span id="TemplateRegistry.get_callbacks-985"><a href="#TemplateRegistry.get_callbacks-985"><span class="linenos"> 985</span></a>                <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span>
+</span><span id="TemplateRegistry.get_callbacks-986"><a href="#TemplateRegistry.get_callbacks-986"><span class="linenos"> 986</span></a>                <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get_callbacks-987"><a href="#TemplateRegistry.get_callbacks-987"><span class="linenos"> 987</span></a>                <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get_callbacks-988"><a href="#TemplateRegistry.get_callbacks-988"><span class="linenos"> 988</span></a>            <span class="p">):</span>
+</span><span id="TemplateRegistry.get_callbacks-989"><a href="#TemplateRegistry.get_callbacks-989"><span class="linenos"> 989</span></a>                <span class="n">value</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get_callbacks-990"><a href="#TemplateRegistry.get_callbacks-990"><span class="linenos"> 990</span></a>                <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get_callbacks-991"><a href="#TemplateRegistry.get_callbacks-991"><span class="linenos"> 991</span></a>                <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_constants</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">value</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get_callbacks-992"><a href="#TemplateRegistry.get_callbacks-992"><span class="linenos"> 992</span></a>                <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry.get_callbacks-993"><a href="#TemplateRegistry.get_callbacks-993"><span class="linenos"> 993</span></a>                    <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-994"><a href="#TemplateRegistry.get_callbacks-994"><span class="linenos"> 994</span></a>                        <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get_callbacks-995"><a href="#TemplateRegistry.get_callbacks-995"><span class="linenos"> 995</span></a>        <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-996"><a href="#TemplateRegistry.get_callbacks-996"><span class="linenos"> 996</span></a>            <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-997"><a href="#TemplateRegistry.get_callbacks-997"><span class="linenos"> 997</span></a>                <span class="k">for</span> <span class="n">schema_string</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.get_callbacks-998"><a href="#TemplateRegistry.get_callbacks-998"><span class="linenos"> 998</span></a>                    <span class="k">if</span> <span class="n">validate</span><span class="p">(</span><span class="n">schema_string</span><span class="p">,</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]):</span>
+</span><span id="TemplateRegistry.get_callbacks-999"><a href="#TemplateRegistry.get_callbacks-999"><span class="linenos"> 999</span></a>                        <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_schemas</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="n">schema_string</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get_callbacks-1000"><a href="#TemplateRegistry.get_callbacks-1000"><span class="linenos">1000</span></a>                        <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">child</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="TemplateRegistry.get_callbacks-1001"><a href="#TemplateRegistry.get_callbacks-1001"><span class="linenos">1001</span></a>                            <span class="k">if</span> <span class="n">callback</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_callbacks-1002"><a href="#TemplateRegistry.get_callbacks-1002"><span class="linenos">1002</span></a>                                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">callback</span><span class="p">)</span>
+</span><span id="TemplateRegistry.get_callbacks-1003"><a href="#TemplateRegistry.get_callbacks-1003"><span class="linenos">1003</span></a>        <span class="k">return</span> <span class="n">result</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Get all callbacks registered for templates matching a message.</p>
+</div>
+
+
+                            </div>
+                            <div id="TemplateRegistry.get_templates" class="classattr">
+                                        <input id="TemplateRegistry.get_templates-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">get_templates</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">client</span><span class="p">:</span> <span class="nb">str</span></span><span class="return-annotation">) -> <span class="n">List</span><span class="p">[</span><span class="n"><a href="#MessageTemplate">MessageTemplate</a></span><span class="p">]</span>:</span></span>
+
+                <label class="view-source-button" for="TemplateRegistry.get_templates-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#TemplateRegistry.get_templates"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="TemplateRegistry.get_templates-1005"><a href="#TemplateRegistry.get_templates-1005"><span class="linenos">1005</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">get_templates</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]:</span>
+</span><span id="TemplateRegistry.get_templates-1006"><a href="#TemplateRegistry.get_templates-1006"><span class="linenos">1006</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get all templates for a client.</span>
+</span><span id="TemplateRegistry.get_templates-1007"><a href="#TemplateRegistry.get_templates-1007"><span class="linenos">1007</span></a>
+</span><span id="TemplateRegistry.get_templates-1008"><a href="#TemplateRegistry.get_templates-1008"><span class="linenos">1008</span></a><span class="sd">        &gt;&gt;&gt; r = TemplateRegistry()</span>
+</span><span id="TemplateRegistry.get_templates-1009"><a href="#TemplateRegistry.get_templates-1009"><span class="linenos">1009</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1010"><a href="#TemplateRegistry.get_templates-1010"><span class="linenos">1010</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 1&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1011"><a href="#TemplateRegistry.get_templates-1011"><span class="linenos">1011</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="TemplateRegistry.get_templates-1012"><a href="#TemplateRegistry.get_templates-1012"><span class="linenos">1012</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},</span>
+</span><span id="TemplateRegistry.get_templates-1013"><a href="#TemplateRegistry.get_templates-1013"><span class="linenos">1013</span></a><span class="sd">        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1014"><a href="#TemplateRegistry.get_templates-1014"><span class="linenos">1014</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 2&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1015"><a href="#TemplateRegistry.get_templates-1015"><span class="linenos">1015</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+</span><span id="TemplateRegistry.get_templates-1016"><a href="#TemplateRegistry.get_templates-1016"><span class="linenos">1016</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},</span>
+</span><span id="TemplateRegistry.get_templates-1017"><a href="#TemplateRegistry.get_templates-1017"><span class="linenos">1017</span></a><span class="sd">        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 3&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1018"><a href="#TemplateRegistry.get_templates-1018"><span class="linenos">1018</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 3&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1019"><a href="#TemplateRegistry.get_templates-1019"><span class="linenos">1019</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+</span><span id="TemplateRegistry.get_templates-1020"><a href="#TemplateRegistry.get_templates-1020"><span class="linenos">1020</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;Client 4&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1021"><a href="#TemplateRegistry.get_templates-1021"><span class="linenos">1021</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 4&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1022"><a href="#TemplateRegistry.get_templates-1022"><span class="linenos">1022</span></a><span class="sd">        [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+</span><span id="TemplateRegistry.get_templates-1023"><a href="#TemplateRegistry.get_templates-1023"><span class="linenos">1023</span></a><span class="sd">        &gt;&gt;&gt; r.insert({}, &#39;Client 5&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1024"><a href="#TemplateRegistry.get_templates-1024"><span class="linenos">1024</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 5&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1025"><a href="#TemplateRegistry.get_templates-1025"><span class="linenos">1025</span></a><span class="sd">        [{}]</span>
+</span><span id="TemplateRegistry.get_templates-1026"><a href="#TemplateRegistry.get_templates-1026"><span class="linenos">1026</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1027"><a href="#TemplateRegistry.get_templates-1027"><span class="linenos">1027</span></a><span class="sd">        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1028"><a href="#TemplateRegistry.get_templates-1028"><span class="linenos">1028</span></a><span class="sd">        &gt;&gt;&gt; r.get_templates(&#39;Client 6&#39;)</span>
+</span><span id="TemplateRegistry.get_templates-1029"><a href="#TemplateRegistry.get_templates-1029"><span class="linenos">1029</span></a><span class="sd">        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</span><span id="TemplateRegistry.get_templates-1030"><a href="#TemplateRegistry.get_templates-1030"><span class="linenos">1030</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="TemplateRegistry.get_templates-1031"><a href="#TemplateRegistry.get_templates-1031"><span class="linenos">1031</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">:</span>
+</span><span id="TemplateRegistry.get_templates-1032"><a href="#TemplateRegistry.get_templates-1032"><span class="linenos">1032</span></a>            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_templates</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="TemplateRegistry.get_templates-1033"><a href="#TemplateRegistry.get_templates-1033"><span class="linenos">1033</span></a>        <span class="k">return</span> <span class="p">[]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Get all templates for a client.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">r</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">)</span>
+<span class="go">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">)</span>
+<span class="go">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v2&#39;</span><span class="p">},</span>
+<span class="gp">... </span>          <span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;integer&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 3&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="s1">&#39;Client 3&#39;</span><span class="p">)</span>
+<span class="go">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">}},</span> <span class="s1">&#39;Client 4&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="s1">&#39;Client 4&#39;</span><span class="p">)</span>
+<span class="go">[{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({},</span> <span class="s1">&#39;Client 5&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="s1">&#39;Client 5&#39;</span><span class="p">)</span>
+<span class="go">[{}]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 6&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s1">&#39;k2&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;v1&#39;</span><span class="p">}},</span> <span class="s1">&#39;Client 6&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="s1">&#39;Client 6&#39;</span><span class="p">)</span>
+<span class="go">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                </section>
+                <section id="BusException">
+                            <input id="BusException-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">BusException</span><wbr>(<span class="base">builtins.Exception</span>):
+
+                <label class="view-source-button" for="BusException-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#BusException"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="BusException-1036"><a href="#BusException-1036"><span class="linenos">1036</span></a><span class="k">class</span><span class="w"> </span><span class="nc">BusException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+</span><span id="BusException-1037"><a href="#BusException-1037"><span class="linenos">1037</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Raise for errors in using message bus.&quot;&quot;&quot;</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Raise for errors in using message bus.</p>
+</div>
+
+
+                </section>
+                <section id="MessageBus">
+                            <input id="MessageBus-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">MessageBus</span>:
+
+                <label class="view-source-button" for="MessageBus-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus-1040"><a href="#MessageBus-1040"><span class="linenos">1040</span></a><span class="k">class</span><span class="w"> </span><span class="nc">MessageBus</span><span class="p">:</span>
+</span><span id="MessageBus-1041"><a href="#MessageBus-1041"><span class="linenos">1041</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Provide an asynchronous message bus.</span>
+</span><span id="MessageBus-1042"><a href="#MessageBus-1042"><span class="linenos">1042</span></a>
+</span><span id="MessageBus-1043"><a href="#MessageBus-1043"><span class="linenos">1043</span></a><span class="sd">    The bus executes asynchronous callbacks for all messages to be received</span>
+</span><span id="MessageBus-1044"><a href="#MessageBus-1044"><span class="linenos">1044</span></a><span class="sd">    by a client. We use a simple callback printing the message in all</span>
+</span><span id="MessageBus-1045"><a href="#MessageBus-1045"><span class="linenos">1045</span></a><span class="sd">    examples:</span>
+</span><span id="MessageBus-1046"><a href="#MessageBus-1046"><span class="linenos">1046</span></a><span class="sd">    &gt;&gt;&gt; def callback_for_receiver(receiver):</span>
+</span><span id="MessageBus-1047"><a href="#MessageBus-1047"><span class="linenos">1047</span></a><span class="sd">    ...     print(f&quot;Creating callback for {receiver}.&quot;)</span>
+</span><span id="MessageBus-1048"><a href="#MessageBus-1048"><span class="linenos">1048</span></a><span class="sd">    ...     async def callback(message):</span>
+</span><span id="MessageBus-1049"><a href="#MessageBus-1049"><span class="linenos">1049</span></a><span class="sd">    ...         print(f&quot;{receiver}: {message}&quot;)</span>
+</span><span id="MessageBus-1050"><a href="#MessageBus-1050"><span class="linenos">1050</span></a><span class="sd">    ...     return callback</span>
+</span><span id="MessageBus-1051"><a href="#MessageBus-1051"><span class="linenos">1051</span></a>
+</span><span id="MessageBus-1052"><a href="#MessageBus-1052"><span class="linenos">1052</span></a><span class="sd">    Clients can be registered at the bus with a name, lists of message</span>
+</span><span id="MessageBus-1053"><a href="#MessageBus-1053"><span class="linenos">1053</span></a><span class="sd">    templates they want to use for sending and receiving and a callback</span>
+</span><span id="MessageBus-1054"><a href="#MessageBus-1054"><span class="linenos">1054</span></a><span class="sd">    function for receiving. An empty list of templates means that the</span>
+</span><span id="MessageBus-1055"><a href="#MessageBus-1055"><span class="linenos">1055</span></a><span class="sd">    client does not want to send or receive any messages, respectively.</span>
+</span><span id="MessageBus-1056"><a href="#MessageBus-1056"><span class="linenos">1056</span></a><span class="sd">    A list with an empty template means that it wants to send arbitrary</span>
+</span><span id="MessageBus-1057"><a href="#MessageBus-1057"><span class="linenos">1057</span></a><span class="sd">    or receive all messages, respectively:</span>
+</span><span id="MessageBus-1058"><a href="#MessageBus-1058"><span class="linenos">1058</span></a><span class="sd">    &gt;&gt;&gt; async def setup(bus):</span>
+</span><span id="MessageBus-1059"><a href="#MessageBus-1059"><span class="linenos">1059</span></a><span class="sd">    ...     print(&quot;Setting up.&quot;)</span>
+</span><span id="MessageBus-1060"><a href="#MessageBus-1060"><span class="linenos">1060</span></a><span class="sd">    ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1061"><a href="#MessageBus-1061"><span class="linenos">1061</span></a><span class="sd">    ...                  [],</span>
+</span><span id="MessageBus-1062"><a href="#MessageBus-1062"><span class="linenos">1062</span></a><span class="sd">    ...                  [([MessageTemplate({})],</span>
+</span><span id="MessageBus-1063"><a href="#MessageBus-1063"><span class="linenos">1063</span></a><span class="sd">    ...                    callback_for_receiver(&#39;Logger&#39;))])</span>
+</span><span id="MessageBus-1064"><a href="#MessageBus-1064"><span class="linenos">1064</span></a><span class="sd">    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1065"><a href="#MessageBus-1065"><span class="linenos">1065</span></a><span class="sd">    ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus-1066"><a href="#MessageBus-1066"><span class="linenos">1066</span></a><span class="sd">    ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1067"><a href="#MessageBus-1067"><span class="linenos">1067</span></a><span class="sd">    ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus-1068"><a href="#MessageBus-1068"><span class="linenos">1068</span></a><span class="sd">    ...                    callback_for_receiver(&#39;Client 1&#39;))])</span>
+</span><span id="MessageBus-1069"><a href="#MessageBus-1069"><span class="linenos">1069</span></a><span class="sd">    ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1070"><a href="#MessageBus-1070"><span class="linenos">1070</span></a><span class="sd">    ...                  [MessageTemplate({})],</span>
+</span><span id="MessageBus-1071"><a href="#MessageBus-1071"><span class="linenos">1071</span></a><span class="sd">    ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1072"><a href="#MessageBus-1072"><span class="linenos">1072</span></a><span class="sd">    ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus-1073"><a href="#MessageBus-1073"><span class="linenos">1073</span></a><span class="sd">    ...                    callback_for_receiver(&#39;Client 2&#39;))])</span>
+</span><span id="MessageBus-1074"><a href="#MessageBus-1074"><span class="linenos">1074</span></a>
+</span><span id="MessageBus-1075"><a href="#MessageBus-1075"><span class="linenos">1075</span></a><span class="sd">    The bus itself is addressed by the empty string. It sends messages for</span>
+</span><span id="MessageBus-1076"><a href="#MessageBus-1076"><span class="linenos">1076</span></a><span class="sd">    each registration and deregestration of a client with a key &#39;event&#39; and</span>
+</span><span id="MessageBus-1077"><a href="#MessageBus-1077"><span class="linenos">1077</span></a><span class="sd">    a value of &#39;registered&#39; or &#39;unregistered&#39;, a key &#39;client&#39; with the</span>
+</span><span id="MessageBus-1078"><a href="#MessageBus-1078"><span class="linenos">1078</span></a><span class="sd">    client&#39;s name as value and for registrations also keys &#39;sends&#39; and</span>
+</span><span id="MessageBus-1079"><a href="#MessageBus-1079"><span class="linenos">1079</span></a><span class="sd">    &#39;receives&#39; with all templates registered for the client for sending and</span>
+</span><span id="MessageBus-1080"><a href="#MessageBus-1080"><span class="linenos">1080</span></a><span class="sd">    receiving.</span>
+</span><span id="MessageBus-1081"><a href="#MessageBus-1081"><span class="linenos">1081</span></a>
+</span><span id="MessageBus-1082"><a href="#MessageBus-1082"><span class="linenos">1082</span></a><span class="sd">    Clients can send to the bus with the send function. Each message has to</span>
+</span><span id="MessageBus-1083"><a href="#MessageBus-1083"><span class="linenos">1083</span></a><span class="sd">    declare a sender. The send templates of that sender are checked for a</span>
+</span><span id="MessageBus-1084"><a href="#MessageBus-1084"><span class="linenos">1084</span></a><span class="sd">    template matching the message. We cannot prevent arbitrary code from</span>
+</span><span id="MessageBus-1085"><a href="#MessageBus-1085"><span class="linenos">1085</span></a><span class="sd">    impersonating any sender, but this should only be done in debugging or</span>
+</span><span id="MessageBus-1086"><a href="#MessageBus-1086"><span class="linenos">1086</span></a><span class="sd">    management situations.</span>
+</span><span id="MessageBus-1087"><a href="#MessageBus-1087"><span class="linenos">1087</span></a>
+</span><span id="MessageBus-1088"><a href="#MessageBus-1088"><span class="linenos">1088</span></a><span class="sd">    Messages that are intended for a specific client by convention have a</span>
+</span><span id="MessageBus-1089"><a href="#MessageBus-1089"><span class="linenos">1089</span></a><span class="sd">    key &#39;target&#39; with the target client&#39;s name as value. Such messages are</span>
+</span><span id="MessageBus-1090"><a href="#MessageBus-1090"><span class="linenos">1090</span></a><span class="sd">    often commands to the client to do something, which is by convention</span>
+</span><span id="MessageBus-1091"><a href="#MessageBus-1091"><span class="linenos">1091</span></a><span class="sd">    indicated by a key &#39;command&#39; with a value that indicates what should be</span>
+</span><span id="MessageBus-1092"><a href="#MessageBus-1092"><span class="linenos">1092</span></a><span class="sd">    done.</span>
+</span><span id="MessageBus-1093"><a href="#MessageBus-1093"><span class="linenos">1093</span></a>
+</span><span id="MessageBus-1094"><a href="#MessageBus-1094"><span class="linenos">1094</span></a><span class="sd">    The bus, for example, reacts to a message with &#39;target&#39;: &#39;&#39; and</span>
+</span><span id="MessageBus-1095"><a href="#MessageBus-1095"><span class="linenos">1095</span></a><span class="sd">    &#39;command&#39;: &#39;get clients&#39; by sending one message for each currently</span>
+</span><span id="MessageBus-1096"><a href="#MessageBus-1096"><span class="linenos">1096</span></a><span class="sd">    registered with complete information about its registered send and</span>
+</span><span id="MessageBus-1097"><a href="#MessageBus-1097"><span class="linenos">1097</span></a><span class="sd">    receive templates.</span>
+</span><span id="MessageBus-1098"><a href="#MessageBus-1098"><span class="linenos">1098</span></a>
+</span><span id="MessageBus-1099"><a href="#MessageBus-1099"><span class="linenos">1099</span></a><span class="sd">    &gt;&gt;&gt; async def send(bus):</span>
+</span><span id="MessageBus-1100"><a href="#MessageBus-1100"><span class="linenos">1100</span></a><span class="sd">    ...     print(&quot;Sending messages.&quot;)</span>
+</span><span id="MessageBus-1101"><a href="#MessageBus-1101"><span class="linenos">1101</span></a><span class="sd">    ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="MessageBus-1102"><a href="#MessageBus-1102"><span class="linenos">1102</span></a><span class="sd">    ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="MessageBus-1103"><a href="#MessageBus-1103"><span class="linenos">1103</span></a><span class="sd">    ...     await bus.send({&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;,</span>
+</span><span id="MessageBus-1104"><a href="#MessageBus-1104"><span class="linenos">1104</span></a><span class="sd">    ...                     &#39;command&#39;: &#39;get clients&#39;})</span>
+</span><span id="MessageBus-1105"><a href="#MessageBus-1105"><span class="linenos">1105</span></a>
+</span><span id="MessageBus-1106"><a href="#MessageBus-1106"><span class="linenos">1106</span></a><span class="sd">    The run function executes the message bus forever. If we want to stop</span>
+</span><span id="MessageBus-1107"><a href="#MessageBus-1107"><span class="linenos">1107</span></a><span class="sd">    it, we have to explicitly cancel the task:</span>
+</span><span id="MessageBus-1108"><a href="#MessageBus-1108"><span class="linenos">1108</span></a><span class="sd">    &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1109"><a href="#MessageBus-1109"><span class="linenos">1109</span></a><span class="sd">    ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1110"><a href="#MessageBus-1110"><span class="linenos">1110</span></a><span class="sd">    ...     await setup(bus)</span>
+</span><span id="MessageBus-1111"><a href="#MessageBus-1111"><span class="linenos">1111</span></a><span class="sd">    ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus-1112"><a href="#MessageBus-1112"><span class="linenos">1112</span></a><span class="sd">    ...     await send(bus)</span>
+</span><span id="MessageBus-1113"><a href="#MessageBus-1113"><span class="linenos">1113</span></a><span class="sd">    ...     await asyncio.sleep(0)</span>
+</span><span id="MessageBus-1114"><a href="#MessageBus-1114"><span class="linenos">1114</span></a><span class="sd">    ...     bus_task.cancel()</span>
+</span><span id="MessageBus-1115"><a href="#MessageBus-1115"><span class="linenos">1115</span></a><span class="sd">    ...     try:</span>
+</span><span id="MessageBus-1116"><a href="#MessageBus-1116"><span class="linenos">1116</span></a><span class="sd">    ...         await bus_task</span>
+</span><span id="MessageBus-1117"><a href="#MessageBus-1117"><span class="linenos">1117</span></a><span class="sd">    ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus-1118"><a href="#MessageBus-1118"><span class="linenos">1118</span></a><span class="sd">    ...         pass</span>
+</span><span id="MessageBus-1119"><a href="#MessageBus-1119"><span class="linenos">1119</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageBus-1120"><a href="#MessageBus-1120"><span class="linenos">1120</span></a><span class="sd">    Setting up.</span>
+</span><span id="MessageBus-1121"><a href="#MessageBus-1121"><span class="linenos">1121</span></a><span class="sd">    Creating callback for Logger.</span>
+</span><span id="MessageBus-1122"><a href="#MessageBus-1122"><span class="linenos">1122</span></a><span class="sd">    Creating callback for Client 1.</span>
+</span><span id="MessageBus-1123"><a href="#MessageBus-1123"><span class="linenos">1123</span></a><span class="sd">    Creating callback for Client 2.</span>
+</span><span id="MessageBus-1124"><a href="#MessageBus-1124"><span class="linenos">1124</span></a><span class="sd">    Sending messages.</span>
+</span><span id="MessageBus-1125"><a href="#MessageBus-1125"><span class="linenos">1125</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="MessageBus-1126"><a href="#MessageBus-1126"><span class="linenos">1126</span></a><span class="sd">             &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1127"><a href="#MessageBus-1127"><span class="linenos">1127</span></a><span class="sd">             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+</span><span id="MessageBus-1128"><a href="#MessageBus-1128"><span class="linenos">1128</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="MessageBus-1129"><a href="#MessageBus-1129"><span class="linenos">1129</span></a><span class="sd">             &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1130"><a href="#MessageBus-1130"><span class="linenos">1130</span></a><span class="sd">             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="MessageBus-1131"><a href="#MessageBus-1131"><span class="linenos">1131</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+</span><span id="MessageBus-1132"><a href="#MessageBus-1132"><span class="linenos">1132</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="MessageBus-1133"><a href="#MessageBus-1133"><span class="linenos">1133</span></a><span class="sd">             &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1134"><a href="#MessageBus-1134"><span class="linenos">1134</span></a><span class="sd">             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>
+</span><span id="MessageBus-1135"><a href="#MessageBus-1135"><span class="linenos">1135</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="MessageBus-1136"><a href="#MessageBus-1136"><span class="linenos">1136</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="MessageBus-1137"><a href="#MessageBus-1137"><span class="linenos">1137</span></a><span class="sd">    Client 1: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="MessageBus-1138"><a href="#MessageBus-1138"><span class="linenos">1138</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;, &#39;command&#39;: &#39;get clients&#39;}</span>
+</span><span id="MessageBus-1139"><a href="#MessageBus-1139"><span class="linenos">1139</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1140"><a href="#MessageBus-1140"><span class="linenos">1140</span></a><span class="sd">             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+</span><span id="MessageBus-1141"><a href="#MessageBus-1141"><span class="linenos">1141</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1142"><a href="#MessageBus-1142"><span class="linenos">1142</span></a><span class="sd">             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="MessageBus-1143"><a href="#MessageBus-1143"><span class="linenos">1143</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+</span><span id="MessageBus-1144"><a href="#MessageBus-1144"><span class="linenos">1144</span></a><span class="sd">    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1145"><a href="#MessageBus-1145"><span class="linenos">1145</span></a><span class="sd">             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>
+</span><span id="MessageBus-1146"><a href="#MessageBus-1146"><span class="linenos">1146</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1147"><a href="#MessageBus-1147"><span class="linenos">1147</span></a>
+</span><span id="MessageBus-1148"><a href="#MessageBus-1148"><span class="linenos">1148</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus-1149"><a href="#MessageBus-1149"><span class="linenos">1149</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise a new bus without clients.</span>
+</span><span id="MessageBus-1150"><a href="#MessageBus-1150"><span class="linenos">1150</span></a>
+</span><span id="MessageBus-1151"><a href="#MessageBus-1151"><span class="linenos">1151</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1152"><a href="#MessageBus-1152"><span class="linenos">1152</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1153"><a href="#MessageBus-1153"><span class="linenos">1153</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus-1154"><a href="#MessageBus-1154"><span class="linenos">1154</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1155"><a href="#MessageBus-1155"><span class="linenos">1155</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Queue</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Queue</span><span class="p">()</span>
+</span><span id="MessageBus-1156"><a href="#MessageBus-1156"><span class="linenos">1156</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="MessageBus-1157"><a href="#MessageBus-1157"><span class="linenos">1157</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="p">:</span> <span class="n">TemplateRegistry</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="MessageBus-1158"><a href="#MessageBus-1158"><span class="linenos">1158</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="p">:</span> <span class="n">TemplateRegistry</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="MessageBus-1159"><a href="#MessageBus-1159"><span class="linenos">1159</span></a>
+</span><span id="MessageBus-1160"><a href="#MessageBus-1160"><span class="linenos">1160</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">register</span><span class="p">(</span>
+</span><span id="MessageBus-1161"><a href="#MessageBus-1161"><span class="linenos">1161</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="MessageBus-1162"><a href="#MessageBus-1162"><span class="linenos">1162</span></a>        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="MessageBus-1163"><a href="#MessageBus-1163"><span class="linenos">1163</span></a>        <span class="n">plugin</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="MessageBus-1164"><a href="#MessageBus-1164"><span class="linenos">1164</span></a>        <span class="n">sends</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">],</span>
+</span><span id="MessageBus-1165"><a href="#MessageBus-1165"><span class="linenos">1165</span></a>        <span class="n">receives</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">],</span> <span class="n">MessageCallback</span><span class="p">]],</span>
+</span><span id="MessageBus-1166"><a href="#MessageBus-1166"><span class="linenos">1166</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus-1167"><a href="#MessageBus-1167"><span class="linenos">1167</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register a client at the message bus.</span>
+</span><span id="MessageBus-1168"><a href="#MessageBus-1168"><span class="linenos">1168</span></a>
+</span><span id="MessageBus-1169"><a href="#MessageBus-1169"><span class="linenos">1169</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus-1170"><a href="#MessageBus-1170"><span class="linenos">1170</span></a><span class="sd">        ...     print(message)</span>
+</span><span id="MessageBus-1171"><a href="#MessageBus-1171"><span class="linenos">1171</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1172"><a href="#MessageBus-1172"><span class="linenos">1172</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1173"><a href="#MessageBus-1173"><span class="linenos">1173</span></a><span class="sd">        ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1174"><a href="#MessageBus-1174"><span class="linenos">1174</span></a><span class="sd">        ...                  [],    # send nothing</span>
+</span><span id="MessageBus-1175"><a href="#MessageBus-1175"><span class="linenos">1175</span></a><span class="sd">        ...                  [([MessageTemplate({})],  # receive everything</span>
+</span><span id="MessageBus-1176"><a href="#MessageBus-1176"><span class="linenos">1176</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1177"><a href="#MessageBus-1177"><span class="linenos">1177</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1178"><a href="#MessageBus-1178"><span class="linenos">1178</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus-1179"><a href="#MessageBus-1179"><span class="linenos">1179</span></a><span class="sd">        ...                      # send with key &#39;k1&#39; and string value</span>
+</span><span id="MessageBus-1180"><a href="#MessageBus-1180"><span class="linenos">1180</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1181"><a href="#MessageBus-1181"><span class="linenos">1181</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus-1182"><a href="#MessageBus-1182"><span class="linenos">1182</span></a><span class="sd">        ...                      # receive for this client</span>
+</span><span id="MessageBus-1183"><a href="#MessageBus-1183"><span class="linenos">1183</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1184"><a href="#MessageBus-1184"><span class="linenos">1184</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1185"><a href="#MessageBus-1185"><span class="linenos">1185</span></a><span class="sd">        ...                  [MessageTemplate({})],  # send arbitrary</span>
+</span><span id="MessageBus-1186"><a href="#MessageBus-1186"><span class="linenos">1186</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1187"><a href="#MessageBus-1187"><span class="linenos">1187</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus-1188"><a href="#MessageBus-1188"><span class="linenos">1188</span></a><span class="sd">        ...                      # receive for this client</span>
+</span><span id="MessageBus-1189"><a href="#MessageBus-1189"><span class="linenos">1189</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1190"><a href="#MessageBus-1190"><span class="linenos">1190</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus-1191"><a href="#MessageBus-1191"><span class="linenos">1191</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1192"><a href="#MessageBus-1192"><span class="linenos">1192</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">client</span><span class="p">:</span>
+</span><span id="MessageBus-1193"><a href="#MessageBus-1193"><span class="linenos">1193</span></a>            <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span><span class="s2">&quot;Client name is not allowed to be empty.&quot;</span><span class="p">)</span>
+</span><span id="MessageBus-1194"><a href="#MessageBus-1194"><span class="linenos">1194</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="MessageBus-1195"><a href="#MessageBus-1195"><span class="linenos">1195</span></a>            <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Client &#39;</span><span class="si">{</span><span class="n">client</span><span class="si">}</span><span class="s2">&#39; already registered at message bus.&quot;</span><span class="p">)</span>
+</span><span id="MessageBus-1196"><a href="#MessageBus-1196"><span class="linenos">1196</span></a>        <span class="n">event</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="MessageBus-1197"><a href="#MessageBus-1197"><span class="linenos">1197</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;registered&quot;</span>
+</span><span id="MessageBus-1198"><a href="#MessageBus-1198"><span class="linenos">1198</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="MessageBus-1199"><a href="#MessageBus-1199"><span class="linenos">1199</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="n">plugin</span>
+</span><span id="MessageBus-1200"><a href="#MessageBus-1200"><span class="linenos">1200</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">plugin</span>
+</span><span id="MessageBus-1201"><a href="#MessageBus-1201"><span class="linenos">1201</span></a>        <span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">sends</span><span class="p">:</span>
+</span><span id="MessageBus-1202"><a href="#MessageBus-1202"><span class="linenos">1202</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1203"><a href="#MessageBus-1203"><span class="linenos">1203</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;sends&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1204"><a href="#MessageBus-1204"><span class="linenos">1204</span></a>        <span class="k">for</span> <span class="n">templates</span><span class="p">,</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">receives</span><span class="p">:</span>
+</span><span id="MessageBus-1205"><a href="#MessageBus-1205"><span class="linenos">1205</span></a>            <span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">templates</span><span class="p">:</span>
+</span><span id="MessageBus-1206"><a href="#MessageBus-1206"><span class="linenos">1206</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
+</span><span id="MessageBus-1207"><a href="#MessageBus-1207"><span class="linenos">1207</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;receives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1208"><a href="#MessageBus-1208"><span class="linenos">1208</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
+</span><span id="MessageBus-1209"><a href="#MessageBus-1209"><span class="linenos">1209</span></a>
+</span><span id="MessageBus-1210"><a href="#MessageBus-1210"><span class="linenos">1210</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">unregister</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus-1211"><a href="#MessageBus-1211"><span class="linenos">1211</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Unregister a client from the message bus.</span>
+</span><span id="MessageBus-1212"><a href="#MessageBus-1212"><span class="linenos">1212</span></a>
+</span><span id="MessageBus-1213"><a href="#MessageBus-1213"><span class="linenos">1213</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus-1214"><a href="#MessageBus-1214"><span class="linenos">1214</span></a><span class="sd">        ...     print(message)</span>
+</span><span id="MessageBus-1215"><a href="#MessageBus-1215"><span class="linenos">1215</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1216"><a href="#MessageBus-1216"><span class="linenos">1216</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1217"><a href="#MessageBus-1217"><span class="linenos">1217</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1218"><a href="#MessageBus-1218"><span class="linenos">1218</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus-1219"><a href="#MessageBus-1219"><span class="linenos">1219</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1220"><a href="#MessageBus-1220"><span class="linenos">1220</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus-1221"><a href="#MessageBus-1221"><span class="linenos">1221</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1222"><a href="#MessageBus-1222"><span class="linenos">1222</span></a><span class="sd">        ...     bus.unregister(&#39;Client 1&#39;)</span>
+</span><span id="MessageBus-1223"><a href="#MessageBus-1223"><span class="linenos">1223</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus-1224"><a href="#MessageBus-1224"><span class="linenos">1224</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1225"><a href="#MessageBus-1225"><span class="linenos">1225</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="MessageBus-1226"><a href="#MessageBus-1226"><span class="linenos">1226</span></a>            <span class="k">return</span>
+</span><span id="MessageBus-1227"><a href="#MessageBus-1227"><span class="linenos">1227</span></a>        <span class="n">event</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="MessageBus-1228"><a href="#MessageBus-1228"><span class="linenos">1228</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;unregistered&quot;</span>
+</span><span id="MessageBus-1229"><a href="#MessageBus-1229"><span class="linenos">1229</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="MessageBus-1230"><a href="#MessageBus-1230"><span class="linenos">1230</span></a>        <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="MessageBus-1231"><a href="#MessageBus-1231"><span class="linenos">1231</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1232"><a href="#MessageBus-1232"><span class="linenos">1232</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1233"><a href="#MessageBus-1233"><span class="linenos">1233</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
+</span><span id="MessageBus-1234"><a href="#MessageBus-1234"><span class="linenos">1234</span></a>
+</span><span id="MessageBus-1235"><a href="#MessageBus-1235"><span class="linenos">1235</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus-1236"><a href="#MessageBus-1236"><span class="linenos">1236</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the message bus forever.</span>
+</span><span id="MessageBus-1237"><a href="#MessageBus-1237"><span class="linenos">1237</span></a>
+</span><span id="MessageBus-1238"><a href="#MessageBus-1238"><span class="linenos">1238</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1239"><a href="#MessageBus-1239"><span class="linenos">1239</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1240"><a href="#MessageBus-1240"><span class="linenos">1240</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus-1241"><a href="#MessageBus-1241"><span class="linenos">1241</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="MessageBus-1242"><a href="#MessageBus-1242"><span class="linenos">1242</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus-1243"><a href="#MessageBus-1243"><span class="linenos">1243</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="MessageBus-1244"><a href="#MessageBus-1244"><span class="linenos">1244</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus-1245"><a href="#MessageBus-1245"><span class="linenos">1245</span></a><span class="sd">        ...         pass</span>
+</span><span id="MessageBus-1246"><a href="#MessageBus-1246"><span class="linenos">1246</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus-1247"><a href="#MessageBus-1247"><span class="linenos">1247</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1248"><a href="#MessageBus-1248"><span class="linenos">1248</span></a>        <span class="n">background_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="MessageBus-1249"><a href="#MessageBus-1249"><span class="linenos">1249</span></a>        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
+</span><span id="MessageBus-1250"><a href="#MessageBus-1250"><span class="linenos">1250</span></a>            <span class="n">message</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
+</span><span id="MessageBus-1251"><a href="#MessageBus-1251"><span class="linenos">1251</span></a>            <span class="k">if</span> <span class="s2">&quot;target&quot;</span> <span class="ow">in</span> <span class="n">message</span> <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;target&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="s2">&quot;command&quot;</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="MessageBus-1252"><a href="#MessageBus-1252"><span class="linenos">1252</span></a>                <span class="k">if</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;get clients&quot;</span><span class="p">:</span>
+</span><span id="MessageBus-1253"><a href="#MessageBus-1253"><span class="linenos">1253</span></a>                    <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="MessageBus-1254"><a href="#MessageBus-1254"><span class="linenos">1254</span></a>                        <span class="n">answer</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="MessageBus-1255"><a href="#MessageBus-1255"><span class="linenos">1255</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="MessageBus-1256"><a href="#MessageBus-1256"><span class="linenos">1256</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="MessageBus-1257"><a href="#MessageBus-1257"><span class="linenos">1257</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;sends&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1258"><a href="#MessageBus-1258"><span class="linenos">1258</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;receives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus-1259"><a href="#MessageBus-1259"><span class="linenos">1259</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
+</span><span id="MessageBus-1260"><a href="#MessageBus-1260"><span class="linenos">1260</span></a>                <span class="k">elif</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;push conf&quot;</span><span class="p">:</span>
+</span><span id="MessageBus-1261"><a href="#MessageBus-1261"><span class="linenos">1261</span></a>                    <span class="n">conf</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="MessageBus-1262"><a href="#MessageBus-1262"><span class="linenos">1262</span></a>                    <span class="k">try</span><span class="p">:</span>
+</span><span id="MessageBus-1263"><a href="#MessageBus-1263"><span class="linenos">1263</span></a>                        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">as</span> <span class="n">conf_file</span><span class="p">:</span>
+</span><span id="MessageBus-1264"><a href="#MessageBus-1264"><span class="linenos">1264</span></a>                            <span class="n">conf</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">conf_file</span><span class="p">)</span>
+</span><span id="MessageBus-1265"><a href="#MessageBus-1265"><span class="linenos">1265</span></a>                    <span class="k">except</span> <span class="p">(</span>
+</span><span id="MessageBus-1266"><a href="#MessageBus-1266"><span class="linenos">1266</span></a>                        <span class="ne">IndexError</span><span class="p">,</span>
+</span><span id="MessageBus-1267"><a href="#MessageBus-1267"><span class="linenos">1267</span></a>                        <span class="ne">FileNotFoundError</span><span class="p">,</span>
+</span><span id="MessageBus-1268"><a href="#MessageBus-1268"><span class="linenos">1268</span></a>                        <span class="n">json</span><span class="o">.</span><span class="n">decoder</span><span class="o">.</span><span class="n">JSONDecodeError</span><span class="p">,</span>
+</span><span id="MessageBus-1269"><a href="#MessageBus-1269"><span class="linenos">1269</span></a>                    <span class="p">):</span>
+</span><span id="MessageBus-1270"><a href="#MessageBus-1270"><span class="linenos">1270</span></a>                        <span class="k">pass</span>
+</span><span id="MessageBus-1271"><a href="#MessageBus-1271"><span class="linenos">1271</span></a>                    <span class="k">if</span> <span class="n">conf</span> <span class="o">==</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;conf&quot;</span><span class="p">]:</span>
+</span><span id="MessageBus-1272"><a href="#MessageBus-1272"><span class="linenos">1272</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;conf unchanged&quot;</span><span class="p">}))</span>
+</span><span id="MessageBus-1273"><a href="#MessageBus-1273"><span class="linenos">1273</span></a>                    <span class="k">else</span><span class="p">:</span>
+</span><span id="MessageBus-1274"><a href="#MessageBus-1274"><span class="linenos">1274</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;conf changed&quot;</span><span class="p">}))</span>
+</span><span id="MessageBus-1275"><a href="#MessageBus-1275"><span class="linenos">1275</span></a>                        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">conf_file</span><span class="p">:</span>
+</span><span id="MessageBus-1276"><a href="#MessageBus-1276"><span class="linenos">1276</span></a>                            <span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;conf&quot;</span><span class="p">],</span> <span class="n">conf_file</span><span class="p">)</span>
+</span><span id="MessageBus-1277"><a href="#MessageBus-1277"><span class="linenos">1277</span></a>            <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="MessageBus-1278"><a href="#MessageBus-1278"><span class="linenos">1278</span></a>                <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">callback</span><span class="p">(</span><span class="n">message</span><span class="p">))</span>
+</span><span id="MessageBus-1279"><a href="#MessageBus-1279"><span class="linenos">1279</span></a>                <span class="n">background_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="MessageBus-1280"><a href="#MessageBus-1280"><span class="linenos">1280</span></a>                <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="n">background_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="MessageBus-1281"><a href="#MessageBus-1281"><span class="linenos">1281</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">task_done</span><span class="p">()</span>
+</span><span id="MessageBus-1282"><a href="#MessageBus-1282"><span class="linenos">1282</span></a>
+</span><span id="MessageBus-1283"><a href="#MessageBus-1283"><span class="linenos">1283</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus-1284"><a href="#MessageBus-1284"><span class="linenos">1284</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send a message to the message bus.</span>
+</span><span id="MessageBus-1285"><a href="#MessageBus-1285"><span class="linenos">1285</span></a>
+</span><span id="MessageBus-1286"><a href="#MessageBus-1286"><span class="linenos">1286</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus-1287"><a href="#MessageBus-1287"><span class="linenos">1287</span></a><span class="sd">        ...     print(f&quot;Got: {message}&quot;)</span>
+</span><span id="MessageBus-1288"><a href="#MessageBus-1288"><span class="linenos">1288</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1289"><a href="#MessageBus-1289"><span class="linenos">1289</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1290"><a href="#MessageBus-1290"><span class="linenos">1290</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1291"><a href="#MessageBus-1291"><span class="linenos">1291</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus-1292"><a href="#MessageBus-1292"><span class="linenos">1292</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1293"><a href="#MessageBus-1293"><span class="linenos">1293</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus-1294"><a href="#MessageBus-1294"><span class="linenos">1294</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1295"><a href="#MessageBus-1295"><span class="linenos">1295</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1296"><a href="#MessageBus-1296"><span class="linenos">1296</span></a><span class="sd">        ...                  [MessageTemplate({})],</span>
+</span><span id="MessageBus-1297"><a href="#MessageBus-1297"><span class="linenos">1297</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1298"><a href="#MessageBus-1298"><span class="linenos">1298</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus-1299"><a href="#MessageBus-1299"><span class="linenos">1299</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1300"><a href="#MessageBus-1300"><span class="linenos">1300</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus-1301"><a href="#MessageBus-1301"><span class="linenos">1301</span></a><span class="sd">        ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="MessageBus-1302"><a href="#MessageBus-1302"><span class="linenos">1302</span></a><span class="sd">        ...                     &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="MessageBus-1303"><a href="#MessageBus-1303"><span class="linenos">1303</span></a><span class="sd">        ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="MessageBus-1304"><a href="#MessageBus-1304"><span class="linenos">1304</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus-1305"><a href="#MessageBus-1305"><span class="linenos">1305</span></a><span class="sd">        ...         await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="MessageBus-1306"><a href="#MessageBus-1306"><span class="linenos">1306</span></a><span class="sd">        ...                         &#39;k1&#39;: 42})</span>
+</span><span id="MessageBus-1307"><a href="#MessageBus-1307"><span class="linenos">1307</span></a><span class="sd">        ...     except BusException as e:</span>
+</span><span id="MessageBus-1308"><a href="#MessageBus-1308"><span class="linenos">1308</span></a><span class="sd">        ...         print(e)</span>
+</span><span id="MessageBus-1309"><a href="#MessageBus-1309"><span class="linenos">1309</span></a><span class="sd">        ...     await asyncio.sleep(0)</span>
+</span><span id="MessageBus-1310"><a href="#MessageBus-1310"><span class="linenos">1310</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="MessageBus-1311"><a href="#MessageBus-1311"><span class="linenos">1311</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus-1312"><a href="#MessageBus-1312"><span class="linenos">1312</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="MessageBus-1313"><a href="#MessageBus-1313"><span class="linenos">1313</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus-1314"><a href="#MessageBus-1314"><span class="linenos">1314</span></a><span class="sd">        ...         pass</span>
+</span><span id="MessageBus-1315"><a href="#MessageBus-1315"><span class="linenos">1315</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageBus-1316"><a href="#MessageBus-1316"><span class="linenos">1316</span></a><span class="sd">        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+</span><span id="MessageBus-1317"><a href="#MessageBus-1317"><span class="linenos">1317</span></a><span class="sd">        not allowed for sender &#39;Client 1&#39;.</span>
+</span><span id="MessageBus-1318"><a href="#MessageBus-1318"><span class="linenos">1318</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="MessageBus-1319"><a href="#MessageBus-1319"><span class="linenos">1319</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="MessageBus-1320"><a href="#MessageBus-1320"><span class="linenos">1320</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1321"><a href="#MessageBus-1321"><span class="linenos">1321</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="MessageBus-1322"><a href="#MessageBus-1322"><span class="linenos">1322</span></a>        <span class="n">sender</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span>
+</span><span id="MessageBus-1323"><a href="#MessageBus-1323"><span class="linenos">1323</span></a>        <span class="k">if</span> <span class="n">sender</span><span class="p">:</span>
+</span><span id="MessageBus-1324"><a href="#MessageBus-1324"><span class="linenos">1324</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="MessageBus-1325"><a href="#MessageBus-1325"><span class="linenos">1325</span></a>                <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span>
+</span><span id="MessageBus-1326"><a href="#MessageBus-1326"><span class="linenos">1326</span></a>                    <span class="sa">f</span><span class="s2">&quot;Message &#39;</span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&#39; not allowed for sender &#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
+</span><span id="MessageBus-1327"><a href="#MessageBus-1327"><span class="linenos">1327</span></a>                <span class="p">)</span>
+</span><span id="MessageBus-1328"><a href="#MessageBus-1328"><span class="linenos">1328</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span><span id="MessageBus-1329"><a href="#MessageBus-1329"><span class="linenos">1329</span></a>
+</span><span id="MessageBus-1330"><a href="#MessageBus-1330"><span class="linenos">1330</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">send_nowait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus-1331"><a href="#MessageBus-1331"><span class="linenos">1331</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send a message to the message bus without blocking.</span>
+</span><span id="MessageBus-1332"><a href="#MessageBus-1332"><span class="linenos">1332</span></a>
+</span><span id="MessageBus-1333"><a href="#MessageBus-1333"><span class="linenos">1333</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus-1334"><a href="#MessageBus-1334"><span class="linenos">1334</span></a><span class="sd">        ...     print(f&quot;Got: {message}&quot;)</span>
+</span><span id="MessageBus-1335"><a href="#MessageBus-1335"><span class="linenos">1335</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus-1336"><a href="#MessageBus-1336"><span class="linenos">1336</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus-1337"><a href="#MessageBus-1337"><span class="linenos">1337</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1338"><a href="#MessageBus-1338"><span class="linenos">1338</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus-1339"><a href="#MessageBus-1339"><span class="linenos">1339</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1340"><a href="#MessageBus-1340"><span class="linenos">1340</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus-1341"><a href="#MessageBus-1341"><span class="linenos">1341</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1342"><a href="#MessageBus-1342"><span class="linenos">1342</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus-1343"><a href="#MessageBus-1343"><span class="linenos">1343</span></a><span class="sd">        ...                  [MessageTemplate({})],</span>
+</span><span id="MessageBus-1344"><a href="#MessageBus-1344"><span class="linenos">1344</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus-1345"><a href="#MessageBus-1345"><span class="linenos">1345</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus-1346"><a href="#MessageBus-1346"><span class="linenos">1346</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus-1347"><a href="#MessageBus-1347"><span class="linenos">1347</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus-1348"><a href="#MessageBus-1348"><span class="linenos">1348</span></a><span class="sd">        ...     bus.send_nowait({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="MessageBus-1349"><a href="#MessageBus-1349"><span class="linenos">1349</span></a><span class="sd">        ...                      &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="MessageBus-1350"><a href="#MessageBus-1350"><span class="linenos">1350</span></a><span class="sd">        ...     bus.send_nowait({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="MessageBus-1351"><a href="#MessageBus-1351"><span class="linenos">1351</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus-1352"><a href="#MessageBus-1352"><span class="linenos">1352</span></a><span class="sd">        ...         bus.send_nowait({&#39;sender&#39;: &#39;Client 1&#39;,</span>
+</span><span id="MessageBus-1353"><a href="#MessageBus-1353"><span class="linenos">1353</span></a><span class="sd">        ...                          &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42})</span>
+</span><span id="MessageBus-1354"><a href="#MessageBus-1354"><span class="linenos">1354</span></a><span class="sd">        ...     except BusException as e:</span>
+</span><span id="MessageBus-1355"><a href="#MessageBus-1355"><span class="linenos">1355</span></a><span class="sd">        ...         print(e)</span>
+</span><span id="MessageBus-1356"><a href="#MessageBus-1356"><span class="linenos">1356</span></a><span class="sd">        ...     await asyncio.sleep(0)</span>
+</span><span id="MessageBus-1357"><a href="#MessageBus-1357"><span class="linenos">1357</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="MessageBus-1358"><a href="#MessageBus-1358"><span class="linenos">1358</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus-1359"><a href="#MessageBus-1359"><span class="linenos">1359</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="MessageBus-1360"><a href="#MessageBus-1360"><span class="linenos">1360</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus-1361"><a href="#MessageBus-1361"><span class="linenos">1361</span></a><span class="sd">        ...         pass</span>
+</span><span id="MessageBus-1362"><a href="#MessageBus-1362"><span class="linenos">1362</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageBus-1363"><a href="#MessageBus-1363"><span class="linenos">1363</span></a><span class="sd">        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+</span><span id="MessageBus-1364"><a href="#MessageBus-1364"><span class="linenos">1364</span></a><span class="sd">        not allowed for sender &#39;Client 1&#39;.</span>
+</span><span id="MessageBus-1365"><a href="#MessageBus-1365"><span class="linenos">1365</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="MessageBus-1366"><a href="#MessageBus-1366"><span class="linenos">1366</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="MessageBus-1367"><a href="#MessageBus-1367"><span class="linenos">1367</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus-1368"><a href="#MessageBus-1368"><span class="linenos">1368</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="MessageBus-1369"><a href="#MessageBus-1369"><span class="linenos">1369</span></a>        <span class="n">sender</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span>
+</span><span id="MessageBus-1370"><a href="#MessageBus-1370"><span class="linenos">1370</span></a>        <span class="k">if</span> <span class="n">sender</span><span class="p">:</span>
+</span><span id="MessageBus-1371"><a href="#MessageBus-1371"><span class="linenos">1371</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="MessageBus-1372"><a href="#MessageBus-1372"><span class="linenos">1372</span></a>                <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span>
+</span><span id="MessageBus-1373"><a href="#MessageBus-1373"><span class="linenos">1373</span></a>                    <span class="sa">f</span><span class="s2">&quot;Message &#39;</span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&#39; not allowed for sender &#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
+</span><span id="MessageBus-1374"><a href="#MessageBus-1374"><span class="linenos">1374</span></a>                <span class="p">)</span>
+</span><span id="MessageBus-1375"><a href="#MessageBus-1375"><span class="linenos">1375</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Provide an asynchronous message bus.</p>
+
+<p>The bus executes asynchronous callbacks for all messages to be received
+by a client. We use a simple callback printing the message in all
+examples:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span><span class="w"> </span><span class="nf">callback_for_receiver</span><span class="p">(</span><span class="n">receiver</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Creating callback for </span><span class="si">{</span><span class="n">receiver</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">receiver</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">return</span> <span class="n">callback</span>
+</code></pre>
+</div>
+
+<p>Clients can be registered at the bus with a name, lists of message
+templates they want to use for sending and receiving and a callback
+function for receiving. An empty list of templates means that the
+client does not want to send or receive any messages, respectively.
+A list with an empty template means that it wants to send arbitrary
+or receive all messages, respectively:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">setup</span><span class="p">(</span><span class="n">bus</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Setting up.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Logger&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({})],</span>
+<span class="gp">... </span>                   <span class="n">callback_for_receiver</span><span class="p">(</span><span class="s1">&#39;Logger&#39;</span><span class="p">))])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback_for_receiver</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">))])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback_for_receiver</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">))])</span>
+</code></pre>
+</div>
+
+<p>The bus itself is addressed by the empty string. It sends messages for
+each registration and deregestration of a client with a key 'event' and
+a value of 'registered' or 'unregistered', a key 'client' with the
+client's name as value and for registrations also keys 'sends' and
+'receives' with all templates registered for the client for sending and
+receiving.</p>
+
+<p>Clients can send to the bus with the send function. Each message has to
+declare a sender. The send templates of that sender are checked for a
+template matching the message. We cannot prevent arbitrary code from
+impersonating any sender, but this should only be done in debugging or
+management situations.</p>
+
+<p>Messages that are intended for a specific client by convention have a
+key 'target' with the target client's name as value. Such messages are
+often commands to the client to do something, which is by convention
+indicated by a key 'command' with a value that indicates what should be
+done.</p>
+
+<p>The bus, for example, reacts to a message with 'target': '' and
+'command': 'get clients' by sending one message for each currently
+registered with complete information about its registered send and
+receive templates.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send</span><span class="p">(</span><span class="n">bus</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Sending messages.&quot;</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;Test&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s1">&#39;command&#39;</span><span class="p">:</span> <span class="s1">&#39;get clients&#39;</span><span class="p">})</span>
+</code></pre>
+</div>
+
+<p>The run function executes the message bus forever. If we want to stop
+it, we have to explicitly cancel the task:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">setup</span><span class="p">(</span><span class="n">bus</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">send</span><span class="p">(</span><span class="n">bus</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">bus_task</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">Setting up.</span>
+<span class="go">Creating callback for Logger.</span>
+<span class="go">Creating callback for Client 1.</span>
+<span class="go">Creating callback for Client 2.</span>
+<span class="go">Sending messages.</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+<span class="go">Client 1: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;, &#39;command&#39;: &#39;get clients&#39;}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>
+<span class="go">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="MessageBus.__init__" class="classattr">
+                                        <input id="MessageBus.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="name">MessageBus</span><span class="signature pdoc-code condensed">()</span>
+
+                <label class="view-source-button" for="MessageBus.__init__-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus.__init__"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus.__init__-1148"><a href="#MessageBus.__init__-1148"><span class="linenos">1148</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus.__init__-1149"><a href="#MessageBus.__init__-1149"><span class="linenos">1149</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise a new bus without clients.</span>
+</span><span id="MessageBus.__init__-1150"><a href="#MessageBus.__init__-1150"><span class="linenos">1150</span></a>
+</span><span id="MessageBus.__init__-1151"><a href="#MessageBus.__init__-1151"><span class="linenos">1151</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus.__init__-1152"><a href="#MessageBus.__init__-1152"><span class="linenos">1152</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus.__init__-1153"><a href="#MessageBus.__init__-1153"><span class="linenos">1153</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus.__init__-1154"><a href="#MessageBus.__init__-1154"><span class="linenos">1154</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus.__init__-1155"><a href="#MessageBus.__init__-1155"><span class="linenos">1155</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="p">:</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Queue</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Queue</span><span class="p">()</span>
+</span><span id="MessageBus.__init__-1156"><a href="#MessageBus.__init__-1156"><span class="linenos">1156</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="MessageBus.__init__-1157"><a href="#MessageBus.__init__-1157"><span class="linenos">1157</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="p">:</span> <span class="n">TemplateRegistry</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span><span id="MessageBus.__init__-1158"><a href="#MessageBus.__init__-1158"><span class="linenos">1158</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="p">:</span> <span class="n">TemplateRegistry</span> <span class="o">=</span> <span class="n">TemplateRegistry</span><span class="p">()</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Initialise a new bus without clients.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageBus.register" class="classattr">
+                                        <input id="MessageBus.register-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">register</span><span class="signature pdoc-code multiline">(<span class="param">    <span class="bp">self</span>,</span><span class="param">        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">   <span class="n">plugin</span><span class="p">:</span> <span class="nb">str</span>,</span><span class="param">   <span class="n">sends</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n"><a href="#MessageTemplate">MessageTemplate</a></span><span class="p">]</span>,</span><span class="param">   <span class="n">receives</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="n"><a href="#MessageTemplate">MessageTemplate</a></span><span class="p">],</span> <span class="n">Callable</span><span class="p">[[</span><span class="n"><a href="#Message">Message</a></span><span class="p">],</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">NoneType</span><span class="p">]]]]</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="MessageBus.register-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus.register"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus.register-1160"><a href="#MessageBus.register-1160"><span class="linenos">1160</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">register</span><span class="p">(</span>
+</span><span id="MessageBus.register-1161"><a href="#MessageBus.register-1161"><span class="linenos">1161</span></a>        <span class="bp">self</span><span class="p">,</span>
+</span><span id="MessageBus.register-1162"><a href="#MessageBus.register-1162"><span class="linenos">1162</span></a>        <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="MessageBus.register-1163"><a href="#MessageBus.register-1163"><span class="linenos">1163</span></a>        <span class="n">plugin</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
+</span><span id="MessageBus.register-1164"><a href="#MessageBus.register-1164"><span class="linenos">1164</span></a>        <span class="n">sends</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">],</span>
+</span><span id="MessageBus.register-1165"><a href="#MessageBus.register-1165"><span class="linenos">1165</span></a>        <span class="n">receives</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="n">Iterable</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">],</span> <span class="n">MessageCallback</span><span class="p">]],</span>
+</span><span id="MessageBus.register-1166"><a href="#MessageBus.register-1166"><span class="linenos">1166</span></a>    <span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus.register-1167"><a href="#MessageBus.register-1167"><span class="linenos">1167</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register a client at the message bus.</span>
+</span><span id="MessageBus.register-1168"><a href="#MessageBus.register-1168"><span class="linenos">1168</span></a>
+</span><span id="MessageBus.register-1169"><a href="#MessageBus.register-1169"><span class="linenos">1169</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus.register-1170"><a href="#MessageBus.register-1170"><span class="linenos">1170</span></a><span class="sd">        ...     print(message)</span>
+</span><span id="MessageBus.register-1171"><a href="#MessageBus.register-1171"><span class="linenos">1171</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus.register-1172"><a href="#MessageBus.register-1172"><span class="linenos">1172</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus.register-1173"><a href="#MessageBus.register-1173"><span class="linenos">1173</span></a><span class="sd">        ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.register-1174"><a href="#MessageBus.register-1174"><span class="linenos">1174</span></a><span class="sd">        ...                  [],    # send nothing</span>
+</span><span id="MessageBus.register-1175"><a href="#MessageBus.register-1175"><span class="linenos">1175</span></a><span class="sd">        ...                  [([MessageTemplate({})],  # receive everything</span>
+</span><span id="MessageBus.register-1176"><a href="#MessageBus.register-1176"><span class="linenos">1176</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.register-1177"><a href="#MessageBus.register-1177"><span class="linenos">1177</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.register-1178"><a href="#MessageBus.register-1178"><span class="linenos">1178</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus.register-1179"><a href="#MessageBus.register-1179"><span class="linenos">1179</span></a><span class="sd">        ...                      # send with key &#39;k1&#39; and string value</span>
+</span><span id="MessageBus.register-1180"><a href="#MessageBus.register-1180"><span class="linenos">1180</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.register-1181"><a href="#MessageBus.register-1181"><span class="linenos">1181</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus.register-1182"><a href="#MessageBus.register-1182"><span class="linenos">1182</span></a><span class="sd">        ...                      # receive for this client</span>
+</span><span id="MessageBus.register-1183"><a href="#MessageBus.register-1183"><span class="linenos">1183</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.register-1184"><a href="#MessageBus.register-1184"><span class="linenos">1184</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.register-1185"><a href="#MessageBus.register-1185"><span class="linenos">1185</span></a><span class="sd">        ...                  [MessageTemplate({})],  # send arbitrary</span>
+</span><span id="MessageBus.register-1186"><a href="#MessageBus.register-1186"><span class="linenos">1186</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.register-1187"><a href="#MessageBus.register-1187"><span class="linenos">1187</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus.register-1188"><a href="#MessageBus.register-1188"><span class="linenos">1188</span></a><span class="sd">        ...                      # receive for this client</span>
+</span><span id="MessageBus.register-1189"><a href="#MessageBus.register-1189"><span class="linenos">1189</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.register-1190"><a href="#MessageBus.register-1190"><span class="linenos">1190</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus.register-1191"><a href="#MessageBus.register-1191"><span class="linenos">1191</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus.register-1192"><a href="#MessageBus.register-1192"><span class="linenos">1192</span></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">client</span><span class="p">:</span>
+</span><span id="MessageBus.register-1193"><a href="#MessageBus.register-1193"><span class="linenos">1193</span></a>            <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span><span class="s2">&quot;Client name is not allowed to be empty.&quot;</span><span class="p">)</span>
+</span><span id="MessageBus.register-1194"><a href="#MessageBus.register-1194"><span class="linenos">1194</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="MessageBus.register-1195"><a href="#MessageBus.register-1195"><span class="linenos">1195</span></a>            <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Client &#39;</span><span class="si">{</span><span class="n">client</span><span class="si">}</span><span class="s2">&#39; already registered at message bus.&quot;</span><span class="p">)</span>
+</span><span id="MessageBus.register-1196"><a href="#MessageBus.register-1196"><span class="linenos">1196</span></a>        <span class="n">event</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="MessageBus.register-1197"><a href="#MessageBus.register-1197"><span class="linenos">1197</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;registered&quot;</span>
+</span><span id="MessageBus.register-1198"><a href="#MessageBus.register-1198"><span class="linenos">1198</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="MessageBus.register-1199"><a href="#MessageBus.register-1199"><span class="linenos">1199</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span> <span class="o">=</span> <span class="n">plugin</span>
+</span><span id="MessageBus.register-1200"><a href="#MessageBus.register-1200"><span class="linenos">1200</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">plugin</span>
+</span><span id="MessageBus.register-1201"><a href="#MessageBus.register-1201"><span class="linenos">1201</span></a>        <span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">sends</span><span class="p">:</span>
+</span><span id="MessageBus.register-1202"><a href="#MessageBus.register-1202"><span class="linenos">1202</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.register-1203"><a href="#MessageBus.register-1203"><span class="linenos">1203</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;sends&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.register-1204"><a href="#MessageBus.register-1204"><span class="linenos">1204</span></a>        <span class="k">for</span> <span class="n">templates</span><span class="p">,</span> <span class="n">callback</span> <span class="ow">in</span> <span class="n">receives</span><span class="p">:</span>
+</span><span id="MessageBus.register-1205"><a href="#MessageBus.register-1205"><span class="linenos">1205</span></a>            <span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">templates</span><span class="p">:</span>
+</span><span id="MessageBus.register-1206"><a href="#MessageBus.register-1206"><span class="linenos">1206</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">client</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
+</span><span id="MessageBus.register-1207"><a href="#MessageBus.register-1207"><span class="linenos">1207</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;receives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.register-1208"><a href="#MessageBus.register-1208"><span class="linenos">1208</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register a client at the message bus.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Logger&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[],</span>    <span class="c1"># send nothing</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({})],</span>  <span class="c1"># receive everything</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                     <span class="c1"># send with key &#39;k1&#39; and string value</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                     <span class="c1"># receive for this client</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({})],</span>  <span class="c1"># send arbitrary</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                     <span class="c1"># receive for this client</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageBus.unregister" class="classattr">
+                                        <input id="MessageBus.unregister-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">unregister</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">client</span><span class="p">:</span> <span class="nb">str</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="MessageBus.unregister-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus.unregister"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus.unregister-1210"><a href="#MessageBus.unregister-1210"><span class="linenos">1210</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">unregister</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus.unregister-1211"><a href="#MessageBus.unregister-1211"><span class="linenos">1211</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Unregister a client from the message bus.</span>
+</span><span id="MessageBus.unregister-1212"><a href="#MessageBus.unregister-1212"><span class="linenos">1212</span></a>
+</span><span id="MessageBus.unregister-1213"><a href="#MessageBus.unregister-1213"><span class="linenos">1213</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus.unregister-1214"><a href="#MessageBus.unregister-1214"><span class="linenos">1214</span></a><span class="sd">        ...     print(message)</span>
+</span><span id="MessageBus.unregister-1215"><a href="#MessageBus.unregister-1215"><span class="linenos">1215</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus.unregister-1216"><a href="#MessageBus.unregister-1216"><span class="linenos">1216</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus.unregister-1217"><a href="#MessageBus.unregister-1217"><span class="linenos">1217</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.unregister-1218"><a href="#MessageBus.unregister-1218"><span class="linenos">1218</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus.unregister-1219"><a href="#MessageBus.unregister-1219"><span class="linenos">1219</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.unregister-1220"><a href="#MessageBus.unregister-1220"><span class="linenos">1220</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus.unregister-1221"><a href="#MessageBus.unregister-1221"><span class="linenos">1221</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.unregister-1222"><a href="#MessageBus.unregister-1222"><span class="linenos">1222</span></a><span class="sd">        ...     bus.unregister(&#39;Client 1&#39;)</span>
+</span><span id="MessageBus.unregister-1223"><a href="#MessageBus.unregister-1223"><span class="linenos">1223</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus.unregister-1224"><a href="#MessageBus.unregister-1224"><span class="linenos">1224</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus.unregister-1225"><a href="#MessageBus.unregister-1225"><span class="linenos">1225</span></a>        <span class="k">if</span> <span class="n">client</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="MessageBus.unregister-1226"><a href="#MessageBus.unregister-1226"><span class="linenos">1226</span></a>            <span class="k">return</span>
+</span><span id="MessageBus.unregister-1227"><a href="#MessageBus.unregister-1227"><span class="linenos">1227</span></a>        <span class="n">event</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="MessageBus.unregister-1228"><a href="#MessageBus.unregister-1228"><span class="linenos">1228</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;unregistered&quot;</span>
+</span><span id="MessageBus.unregister-1229"><a href="#MessageBus.unregister-1229"><span class="linenos">1229</span></a>        <span class="n">event</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="MessageBus.unregister-1230"><a href="#MessageBus.unregister-1230"><span class="linenos">1230</span></a>        <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="MessageBus.unregister-1231"><a href="#MessageBus.unregister-1231"><span class="linenos">1231</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.unregister-1232"><a href="#MessageBus.unregister-1232"><span class="linenos">1232</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.unregister-1233"><a href="#MessageBus.unregister-1233"><span class="linenos">1233</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Unregister a client from the message bus.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">unregister</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageBus.run" class="classattr">
+                                        <input id="MessageBus.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="MessageBus.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus.run-1235"><a href="#MessageBus.run-1235"><span class="linenos">1235</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus.run-1236"><a href="#MessageBus.run-1236"><span class="linenos">1236</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the message bus forever.</span>
+</span><span id="MessageBus.run-1237"><a href="#MessageBus.run-1237"><span class="linenos">1237</span></a>
+</span><span id="MessageBus.run-1238"><a href="#MessageBus.run-1238"><span class="linenos">1238</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus.run-1239"><a href="#MessageBus.run-1239"><span class="linenos">1239</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus.run-1240"><a href="#MessageBus.run-1240"><span class="linenos">1240</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus.run-1241"><a href="#MessageBus.run-1241"><span class="linenos">1241</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="MessageBus.run-1242"><a href="#MessageBus.run-1242"><span class="linenos">1242</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus.run-1243"><a href="#MessageBus.run-1243"><span class="linenos">1243</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="MessageBus.run-1244"><a href="#MessageBus.run-1244"><span class="linenos">1244</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus.run-1245"><a href="#MessageBus.run-1245"><span class="linenos">1245</span></a><span class="sd">        ...         pass</span>
+</span><span id="MessageBus.run-1246"><a href="#MessageBus.run-1246"><span class="linenos">1246</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())</span>
+</span><span id="MessageBus.run-1247"><a href="#MessageBus.run-1247"><span class="linenos">1247</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus.run-1248"><a href="#MessageBus.run-1248"><span class="linenos">1248</span></a>        <span class="n">background_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="MessageBus.run-1249"><a href="#MessageBus.run-1249"><span class="linenos">1249</span></a>        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
+</span><span id="MessageBus.run-1250"><a href="#MessageBus.run-1250"><span class="linenos">1250</span></a>            <span class="n">message</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
+</span><span id="MessageBus.run-1251"><a href="#MessageBus.run-1251"><span class="linenos">1251</span></a>            <span class="k">if</span> <span class="s2">&quot;target&quot;</span> <span class="ow">in</span> <span class="n">message</span> <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;target&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="s2">&quot;command&quot;</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="MessageBus.run-1252"><a href="#MessageBus.run-1252"><span class="linenos">1252</span></a>                <span class="k">if</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;get clients&quot;</span><span class="p">:</span>
+</span><span id="MessageBus.run-1253"><a href="#MessageBus.run-1253"><span class="linenos">1253</span></a>                    <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+</span><span id="MessageBus.run-1254"><a href="#MessageBus.run-1254"><span class="linenos">1254</span></a>                        <span class="n">answer</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
+</span><span id="MessageBus.run-1255"><a href="#MessageBus.run-1255"><span class="linenos">1255</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;client&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
+</span><span id="MessageBus.run-1256"><a href="#MessageBus.run-1256"><span class="linenos">1256</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;plugin&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>
+</span><span id="MessageBus.run-1257"><a href="#MessageBus.run-1257"><span class="linenos">1257</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;sends&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.run-1258"><a href="#MessageBus.run-1258"><span class="linenos">1258</span></a>                        <span class="n">answer</span><span class="p">[</span><span class="s2">&quot;receives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_templates</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
+</span><span id="MessageBus.run-1259"><a href="#MessageBus.run-1259"><span class="linenos">1259</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
+</span><span id="MessageBus.run-1260"><a href="#MessageBus.run-1260"><span class="linenos">1260</span></a>                <span class="k">elif</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;push conf&quot;</span><span class="p">:</span>
+</span><span id="MessageBus.run-1261"><a href="#MessageBus.run-1261"><span class="linenos">1261</span></a>                    <span class="n">conf</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="MessageBus.run-1262"><a href="#MessageBus.run-1262"><span class="linenos">1262</span></a>                    <span class="k">try</span><span class="p">:</span>
+</span><span id="MessageBus.run-1263"><a href="#MessageBus.run-1263"><span class="linenos">1263</span></a>                        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">as</span> <span class="n">conf_file</span><span class="p">:</span>
+</span><span id="MessageBus.run-1264"><a href="#MessageBus.run-1264"><span class="linenos">1264</span></a>                            <span class="n">conf</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">conf_file</span><span class="p">)</span>
+</span><span id="MessageBus.run-1265"><a href="#MessageBus.run-1265"><span class="linenos">1265</span></a>                    <span class="k">except</span> <span class="p">(</span>
+</span><span id="MessageBus.run-1266"><a href="#MessageBus.run-1266"><span class="linenos">1266</span></a>                        <span class="ne">IndexError</span><span class="p">,</span>
+</span><span id="MessageBus.run-1267"><a href="#MessageBus.run-1267"><span class="linenos">1267</span></a>                        <span class="ne">FileNotFoundError</span><span class="p">,</span>
+</span><span id="MessageBus.run-1268"><a href="#MessageBus.run-1268"><span class="linenos">1268</span></a>                        <span class="n">json</span><span class="o">.</span><span class="n">decoder</span><span class="o">.</span><span class="n">JSONDecodeError</span><span class="p">,</span>
+</span><span id="MessageBus.run-1269"><a href="#MessageBus.run-1269"><span class="linenos">1269</span></a>                    <span class="p">):</span>
+</span><span id="MessageBus.run-1270"><a href="#MessageBus.run-1270"><span class="linenos">1270</span></a>                        <span class="k">pass</span>
+</span><span id="MessageBus.run-1271"><a href="#MessageBus.run-1271"><span class="linenos">1271</span></a>                    <span class="k">if</span> <span class="n">conf</span> <span class="o">==</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;conf&quot;</span><span class="p">]:</span>
+</span><span id="MessageBus.run-1272"><a href="#MessageBus.run-1272"><span class="linenos">1272</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;conf unchanged&quot;</span><span class="p">}))</span>
+</span><span id="MessageBus.run-1273"><a href="#MessageBus.run-1273"><span class="linenos">1273</span></a>                    <span class="k">else</span><span class="p">:</span>
+</span><span id="MessageBus.run-1274"><a href="#MessageBus.run-1274"><span class="linenos">1274</span></a>                        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;conf changed&quot;</span><span class="p">}))</span>
+</span><span id="MessageBus.run-1275"><a href="#MessageBus.run-1275"><span class="linenos">1275</span></a>                        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">conf_file</span><span class="p">:</span>
+</span><span id="MessageBus.run-1276"><a href="#MessageBus.run-1276"><span class="linenos">1276</span></a>                            <span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;conf&quot;</span><span class="p">],</span> <span class="n">conf_file</span><span class="p">)</span>
+</span><span id="MessageBus.run-1277"><a href="#MessageBus.run-1277"><span class="linenos">1277</span></a>            <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_recv_reg</span><span class="o">.</span><span class="n">get_callbacks</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+</span><span id="MessageBus.run-1278"><a href="#MessageBus.run-1278"><span class="linenos">1278</span></a>                <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">callback</span><span class="p">(</span><span class="n">message</span><span class="p">))</span>
+</span><span id="MessageBus.run-1279"><a href="#MessageBus.run-1279"><span class="linenos">1279</span></a>                <span class="n">background_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="MessageBus.run-1280"><a href="#MessageBus.run-1280"><span class="linenos">1280</span></a>                <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="n">background_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="MessageBus.run-1281"><a href="#MessageBus.run-1281"><span class="linenos">1281</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">task_done</span><span class="p">()</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run the message bus forever.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="n">bus_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="n">bus_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">bus_task</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageBus.send" class="classattr">
+                                        <input id="MessageBus.send-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">send</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="MessageBus.send-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus.send"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus.send-1283"><a href="#MessageBus.send-1283"><span class="linenos">1283</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus.send-1284"><a href="#MessageBus.send-1284"><span class="linenos">1284</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send a message to the message bus.</span>
+</span><span id="MessageBus.send-1285"><a href="#MessageBus.send-1285"><span class="linenos">1285</span></a>
+</span><span id="MessageBus.send-1286"><a href="#MessageBus.send-1286"><span class="linenos">1286</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus.send-1287"><a href="#MessageBus.send-1287"><span class="linenos">1287</span></a><span class="sd">        ...     print(f&quot;Got: {message}&quot;)</span>
+</span><span id="MessageBus.send-1288"><a href="#MessageBus.send-1288"><span class="linenos">1288</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus.send-1289"><a href="#MessageBus.send-1289"><span class="linenos">1289</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus.send-1290"><a href="#MessageBus.send-1290"><span class="linenos">1290</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.send-1291"><a href="#MessageBus.send-1291"><span class="linenos">1291</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus.send-1292"><a href="#MessageBus.send-1292"><span class="linenos">1292</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.send-1293"><a href="#MessageBus.send-1293"><span class="linenos">1293</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus.send-1294"><a href="#MessageBus.send-1294"><span class="linenos">1294</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.send-1295"><a href="#MessageBus.send-1295"><span class="linenos">1295</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.send-1296"><a href="#MessageBus.send-1296"><span class="linenos">1296</span></a><span class="sd">        ...                  [MessageTemplate({})],</span>
+</span><span id="MessageBus.send-1297"><a href="#MessageBus.send-1297"><span class="linenos">1297</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.send-1298"><a href="#MessageBus.send-1298"><span class="linenos">1298</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus.send-1299"><a href="#MessageBus.send-1299"><span class="linenos">1299</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.send-1300"><a href="#MessageBus.send-1300"><span class="linenos">1300</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus.send-1301"><a href="#MessageBus.send-1301"><span class="linenos">1301</span></a><span class="sd">        ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="MessageBus.send-1302"><a href="#MessageBus.send-1302"><span class="linenos">1302</span></a><span class="sd">        ...                     &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="MessageBus.send-1303"><a href="#MessageBus.send-1303"><span class="linenos">1303</span></a><span class="sd">        ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="MessageBus.send-1304"><a href="#MessageBus.send-1304"><span class="linenos">1304</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus.send-1305"><a href="#MessageBus.send-1305"><span class="linenos">1305</span></a><span class="sd">        ...         await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="MessageBus.send-1306"><a href="#MessageBus.send-1306"><span class="linenos">1306</span></a><span class="sd">        ...                         &#39;k1&#39;: 42})</span>
+</span><span id="MessageBus.send-1307"><a href="#MessageBus.send-1307"><span class="linenos">1307</span></a><span class="sd">        ...     except BusException as e:</span>
+</span><span id="MessageBus.send-1308"><a href="#MessageBus.send-1308"><span class="linenos">1308</span></a><span class="sd">        ...         print(e)</span>
+</span><span id="MessageBus.send-1309"><a href="#MessageBus.send-1309"><span class="linenos">1309</span></a><span class="sd">        ...     await asyncio.sleep(0)</span>
+</span><span id="MessageBus.send-1310"><a href="#MessageBus.send-1310"><span class="linenos">1310</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="MessageBus.send-1311"><a href="#MessageBus.send-1311"><span class="linenos">1311</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus.send-1312"><a href="#MessageBus.send-1312"><span class="linenos">1312</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="MessageBus.send-1313"><a href="#MessageBus.send-1313"><span class="linenos">1313</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus.send-1314"><a href="#MessageBus.send-1314"><span class="linenos">1314</span></a><span class="sd">        ...         pass</span>
+</span><span id="MessageBus.send-1315"><a href="#MessageBus.send-1315"><span class="linenos">1315</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageBus.send-1316"><a href="#MessageBus.send-1316"><span class="linenos">1316</span></a><span class="sd">        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+</span><span id="MessageBus.send-1317"><a href="#MessageBus.send-1317"><span class="linenos">1317</span></a><span class="sd">        not allowed for sender &#39;Client 1&#39;.</span>
+</span><span id="MessageBus.send-1318"><a href="#MessageBus.send-1318"><span class="linenos">1318</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="MessageBus.send-1319"><a href="#MessageBus.send-1319"><span class="linenos">1319</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="MessageBus.send-1320"><a href="#MessageBus.send-1320"><span class="linenos">1320</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus.send-1321"><a href="#MessageBus.send-1321"><span class="linenos">1321</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="MessageBus.send-1322"><a href="#MessageBus.send-1322"><span class="linenos">1322</span></a>        <span class="n">sender</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span>
+</span><span id="MessageBus.send-1323"><a href="#MessageBus.send-1323"><span class="linenos">1323</span></a>        <span class="k">if</span> <span class="n">sender</span><span class="p">:</span>
+</span><span id="MessageBus.send-1324"><a href="#MessageBus.send-1324"><span class="linenos">1324</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="MessageBus.send-1325"><a href="#MessageBus.send-1325"><span class="linenos">1325</span></a>                <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span>
+</span><span id="MessageBus.send-1326"><a href="#MessageBus.send-1326"><span class="linenos">1326</span></a>                    <span class="sa">f</span><span class="s2">&quot;Message &#39;</span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&#39; not allowed for sender &#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
+</span><span id="MessageBus.send-1327"><a href="#MessageBus.send-1327"><span class="linenos">1327</span></a>                <span class="p">)</span>
+</span><span id="MessageBus.send-1328"><a href="#MessageBus.send-1328"><span class="linenos">1328</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send a message to the message bus.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Got: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;Test&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                        <span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">BusException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">bus_task</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+<span class="go">not allowed for sender &#39;Client 1&#39;.</span>
+<span class="go">Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+<span class="go">Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                            <div id="MessageBus.send_nowait" class="classattr">
+                                        <input id="MessageBus.send_nowait-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">send_nowait</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="n">message</span><span class="p">:</span> <span class="n"><a href="#Message">Message</a></span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="MessageBus.send_nowait-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#MessageBus.send_nowait"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="MessageBus.send_nowait-1330"><a href="#MessageBus.send_nowait-1330"><span class="linenos">1330</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">send_nowait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="MessageBus.send_nowait-1331"><a href="#MessageBus.send_nowait-1331"><span class="linenos">1331</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send a message to the message bus without blocking.</span>
+</span><span id="MessageBus.send_nowait-1332"><a href="#MessageBus.send_nowait-1332"><span class="linenos">1332</span></a>
+</span><span id="MessageBus.send_nowait-1333"><a href="#MessageBus.send_nowait-1333"><span class="linenos">1333</span></a><span class="sd">        &gt;&gt;&gt; async def callback(message):</span>
+</span><span id="MessageBus.send_nowait-1334"><a href="#MessageBus.send_nowait-1334"><span class="linenos">1334</span></a><span class="sd">        ...     print(f&quot;Got: {message}&quot;)</span>
+</span><span id="MessageBus.send_nowait-1335"><a href="#MessageBus.send_nowait-1335"><span class="linenos">1335</span></a><span class="sd">        &gt;&gt;&gt; async def main():</span>
+</span><span id="MessageBus.send_nowait-1336"><a href="#MessageBus.send_nowait-1336"><span class="linenos">1336</span></a><span class="sd">        ...     bus = MessageBus()</span>
+</span><span id="MessageBus.send_nowait-1337"><a href="#MessageBus.send_nowait-1337"><span class="linenos">1337</span></a><span class="sd">        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.send_nowait-1338"><a href="#MessageBus.send_nowait-1338"><span class="linenos">1338</span></a><span class="sd">        ...                  [MessageTemplate({&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}})],</span>
+</span><span id="MessageBus.send_nowait-1339"><a href="#MessageBus.send_nowait-1339"><span class="linenos">1339</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.send_nowait-1340"><a href="#MessageBus.send_nowait-1340"><span class="linenos">1340</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 1&#39;}})],</span>
+</span><span id="MessageBus.send_nowait-1341"><a href="#MessageBus.send_nowait-1341"><span class="linenos">1341</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.send_nowait-1342"><a href="#MessageBus.send_nowait-1342"><span class="linenos">1342</span></a><span class="sd">        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,</span>
+</span><span id="MessageBus.send_nowait-1343"><a href="#MessageBus.send_nowait-1343"><span class="linenos">1343</span></a><span class="sd">        ...                  [MessageTemplate({})],</span>
+</span><span id="MessageBus.send_nowait-1344"><a href="#MessageBus.send_nowait-1344"><span class="linenos">1344</span></a><span class="sd">        ...                  [([MessageTemplate({&#39;target&#39;:</span>
+</span><span id="MessageBus.send_nowait-1345"><a href="#MessageBus.send_nowait-1345"><span class="linenos">1345</span></a><span class="sd">        ...                                      {&#39;const&#39;: &#39;Client 2&#39;}})],</span>
+</span><span id="MessageBus.send_nowait-1346"><a href="#MessageBus.send_nowait-1346"><span class="linenos">1346</span></a><span class="sd">        ...                    callback)])</span>
+</span><span id="MessageBus.send_nowait-1347"><a href="#MessageBus.send_nowait-1347"><span class="linenos">1347</span></a><span class="sd">        ...     bus_task = asyncio.create_task(bus.run())</span>
+</span><span id="MessageBus.send_nowait-1348"><a href="#MessageBus.send_nowait-1348"><span class="linenos">1348</span></a><span class="sd">        ...     bus.send_nowait({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,</span>
+</span><span id="MessageBus.send_nowait-1349"><a href="#MessageBus.send_nowait-1349"><span class="linenos">1349</span></a><span class="sd">        ...                      &#39;k1&#39;: &#39;Test&#39;})</span>
+</span><span id="MessageBus.send_nowait-1350"><a href="#MessageBus.send_nowait-1350"><span class="linenos">1350</span></a><span class="sd">        ...     bus.send_nowait({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})</span>
+</span><span id="MessageBus.send_nowait-1351"><a href="#MessageBus.send_nowait-1351"><span class="linenos">1351</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus.send_nowait-1352"><a href="#MessageBus.send_nowait-1352"><span class="linenos">1352</span></a><span class="sd">        ...         bus.send_nowait({&#39;sender&#39;: &#39;Client 1&#39;,</span>
+</span><span id="MessageBus.send_nowait-1353"><a href="#MessageBus.send_nowait-1353"><span class="linenos">1353</span></a><span class="sd">        ...                          &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42})</span>
+</span><span id="MessageBus.send_nowait-1354"><a href="#MessageBus.send_nowait-1354"><span class="linenos">1354</span></a><span class="sd">        ...     except BusException as e:</span>
+</span><span id="MessageBus.send_nowait-1355"><a href="#MessageBus.send_nowait-1355"><span class="linenos">1355</span></a><span class="sd">        ...         print(e)</span>
+</span><span id="MessageBus.send_nowait-1356"><a href="#MessageBus.send_nowait-1356"><span class="linenos">1356</span></a><span class="sd">        ...     await asyncio.sleep(0)</span>
+</span><span id="MessageBus.send_nowait-1357"><a href="#MessageBus.send_nowait-1357"><span class="linenos">1357</span></a><span class="sd">        ...     bus_task.cancel()</span>
+</span><span id="MessageBus.send_nowait-1358"><a href="#MessageBus.send_nowait-1358"><span class="linenos">1358</span></a><span class="sd">        ...     try:</span>
+</span><span id="MessageBus.send_nowait-1359"><a href="#MessageBus.send_nowait-1359"><span class="linenos">1359</span></a><span class="sd">        ...         await bus_task</span>
+</span><span id="MessageBus.send_nowait-1360"><a href="#MessageBus.send_nowait-1360"><span class="linenos">1360</span></a><span class="sd">        ...     except asyncio.exceptions.CancelledError:</span>
+</span><span id="MessageBus.send_nowait-1361"><a href="#MessageBus.send_nowait-1361"><span class="linenos">1361</span></a><span class="sd">        ...         pass</span>
+</span><span id="MessageBus.send_nowait-1362"><a href="#MessageBus.send_nowait-1362"><span class="linenos">1362</span></a><span class="sd">        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="MessageBus.send_nowait-1363"><a href="#MessageBus.send_nowait-1363"><span class="linenos">1363</span></a><span class="sd">        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+</span><span id="MessageBus.send_nowait-1364"><a href="#MessageBus.send_nowait-1364"><span class="linenos">1364</span></a><span class="sd">        not allowed for sender &#39;Client 1&#39;.</span>
+</span><span id="MessageBus.send_nowait-1365"><a href="#MessageBus.send_nowait-1365"><span class="linenos">1365</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+</span><span id="MessageBus.send_nowait-1366"><a href="#MessageBus.send_nowait-1366"><span class="linenos">1366</span></a><span class="sd">        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</span><span id="MessageBus.send_nowait-1367"><a href="#MessageBus.send_nowait-1367"><span class="linenos">1367</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="MessageBus.send_nowait-1368"><a href="#MessageBus.send_nowait-1368"><span class="linenos">1368</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="MessageBus.send_nowait-1369"><a href="#MessageBus.send_nowait-1369"><span class="linenos">1369</span></a>        <span class="n">sender</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span>
+</span><span id="MessageBus.send_nowait-1370"><a href="#MessageBus.send_nowait-1370"><span class="linenos">1370</span></a>        <span class="k">if</span> <span class="n">sender</span><span class="p">:</span>
+</span><span id="MessageBus.send_nowait-1371"><a href="#MessageBus.send_nowait-1371"><span class="linenos">1371</span></a>            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_send_reg</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+</span><span id="MessageBus.send_nowait-1372"><a href="#MessageBus.send_nowait-1372"><span class="linenos">1372</span></a>                <span class="k">raise</span> <span class="n">BusException</span><span class="p">(</span>
+</span><span id="MessageBus.send_nowait-1373"><a href="#MessageBus.send_nowait-1373"><span class="linenos">1373</span></a>                    <span class="sa">f</span><span class="s2">&quot;Message &#39;</span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&#39; not allowed for sender &#39;</span><span class="si">{</span><span class="n">sender</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
+</span><span id="MessageBus.send_nowait-1374"><a href="#MessageBus.send_nowait-1374"><span class="linenos">1374</span></a>                <span class="p">)</span>
+</span><span id="MessageBus.send_nowait-1375"><a href="#MessageBus.send_nowait-1375"><span class="linenos">1375</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_queue</span><span class="o">.</span><span class="n">put_nowait</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send a message to the message bus without blocking.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">message</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Got: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
+<span class="gp">... </span>    <span class="n">bus</span> <span class="o">=</span> <span class="n">MessageBus</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;string&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;Test Plugin&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                 <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({})],</span>
+<span class="gp">... </span>                 <span class="p">[([</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s1">&#39;target&#39;</span><span class="p">:</span>
+<span class="gp">... </span>                                     <span class="p">{</span><span class="s1">&#39;const&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">}})],</span>
+<span class="gp">... </span>                   <span class="n">callback</span><span class="p">)])</span>
+<span class="gp">... </span>    <span class="n">bus_task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">bus</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">send_nowait</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                     <span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="s1">&#39;Test&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="n">bus</span><span class="o">.</span><span class="n">send_nowait</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="n">bus</span><span class="o">.</span><span class="n">send_nowait</span><span class="p">({</span><span class="s1">&#39;sender&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 1&#39;</span><span class="p">,</span>
+<span class="gp">... </span>                         <span class="s1">&#39;target&#39;</span><span class="p">:</span> <span class="s1">&#39;Client 2&#39;</span><span class="p">,</span> <span class="s1">&#39;k1&#39;</span><span class="p">:</span> <span class="mi">42</span><span class="p">})</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">BusException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="gp">... </span>    <span class="n">bus_task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
+<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">await</span> <span class="n">bus_task</span>
+<span class="gp">... </span>    <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
+<span class="gp">... </span>        <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>  <span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>
+<span class="go">not allowed for sender &#39;Client 1&#39;.</span>
+<span class="go">Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>
+<span class="go">Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "../search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `../${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi/pluginregistry.html b/doc/api/controlpi/pluginregistry.html
new file mode 100644 (file)
index 0000000..c073270
--- /dev/null
@@ -0,0 +1,684 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi.pluginregistry API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="../controlpi.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;controlpi</a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="class" href="#PluginRegistry">PluginRegistry</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="function" href="#PluginRegistry.__init__">PluginRegistry</a>
+                        </li>
+                </ul>
+
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+<a href="./../controlpi.html">controlpi</a><wbr>.pluginregistry    </h1>
+
+                        <div class="docstring"><p>Provide a generic plugin system.</p>
+
+<p>The class PluginRegistry is initialised with the name of a namespace
+package and a base class.</p>
+
+<p>All modules in the namespace package are loaded. These modules can be
+included in different distribution packages, which allows to dynamically
+add plugins to the system without changing any code.</p>
+
+<p>Afterwards, all (direct and indirect) subclasses of the base class are
+registered as plugins under their class name. Class names should be unique,
+which cannot be programmatically enforced.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">BasePlugin</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">Plugin1</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">Plugin2</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">registry</span> <span class="o">=</span> <span class="n">PluginRegistry</span><span class="p">(</span><span class="s1">&#39;importlib&#39;</span><span class="p">,</span> <span class="n">BasePlugin</span><span class="p">)</span>
+</code></pre>
+</div>
+
+<p>The registry provides a generic mapping interface with the class names as
+keys and the classes as values.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">registry</span><span class="p">))</span>
+<span class="go">2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">registry</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">registry</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+<span class="go">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">if</span> <span class="s1">&#39;Plugin1&#39;</span> <span class="ow">in</span> <span class="n">registry</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;Plugin1&#39; is in registry.&quot;</span><span class="p">)</span>
+<span class="go">&#39;Plugin1&#39; is in registry.</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">p1</span> <span class="o">=</span> <span class="n">registry</span><span class="p">[</span><span class="s1">&#39;Plugin1&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">i1</span> <span class="o">=</span> <span class="n">p1</span><span class="p">()</span>
+</code></pre>
+</div>
+</div>
+
+                        <input id="mod-pluginregistry-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-pluginregistry-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">  1</span></a><span class="sd">&quot;&quot;&quot;Provide a generic plugin system.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">  2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">  3</span></a><span class="sd">The class PluginRegistry is initialised with the name of a namespace</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">  4</span></a><span class="sd">package and a base class.</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">  5</span></a>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">  6</span></a><span class="sd">All modules in the namespace package are loaded. These modules can be</span>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">  7</span></a><span class="sd">included in different distribution packages, which allows to dynamically</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">  8</span></a><span class="sd">add plugins to the system without changing any code.</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">  9</span></a>
+</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="sd">Afterwards, all (direct and indirect) subclasses of the base class are</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="sd">registered as plugins under their class name. Class names should be unique,</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a><span class="sd">which cannot be programmatically enforced.</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a>
+</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="sd">&gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a><span class="sd">...     pass</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="sd">&gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="sd">...     pass</span>
+</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="sd">&gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a><span class="sd">...     pass</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a><span class="sd">&gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a>
+</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="sd">The registry provides a generic mapping interface with the class names as</span>
+</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a><span class="sd">keys and the classes as values.</span>
+</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a>
+</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a><span class="sd">&gt;&gt;&gt; print(len(registry))</span>
+</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a><span class="sd">2</span>
+</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="sd">&gt;&gt;&gt; for name in registry:</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a><span class="sd">...     print(f&quot;{name}: {registry[name]}&quot;)</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="sd">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a><span class="sd">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="sd">&gt;&gt;&gt; if &#39;Plugin1&#39; in registry:</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a><span class="sd">...     print(f&quot;&#39;Plugin1&#39; is in registry.&quot;)</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a><span class="sd">&#39;Plugin1&#39; is in registry.</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a><span class="sd">&gt;&gt;&gt; p1 = registry[&#39;Plugin1&#39;]</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a><span class="sd">&gt;&gt;&gt; i1 = p1()</span>
+</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a>
+</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">importlib</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">pkgutil</span>
+</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">collections.abc</span>
+</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a>
+</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a>
+</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a><span class="k">class</span><span class="w"> </span><span class="nc">PluginRegistry</span><span class="p">(</span><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Mapping</span><span class="p">):</span>
+</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Provide a registry for plugins.</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a>
+</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="sd">    Initialise the registry by loading all modules in the given namespace</span>
+</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="sd">    package and then registering all subclasses of the given base class as</span>
+</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a><span class="sd">    plugins (only simulated here – the code for Plugin1 and Plugin2 should</span>
+</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="sd">    be in modules in the given namespace package in real applications):</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="sd">    &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a><span class="sd">    ...     pass</span>
+</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a><span class="sd">    &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a><span class="sd">    ...     pass</span>
+</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a><span class="sd">    &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a><span class="sd">    ...     pass</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a><span class="sd">    &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a>
+</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a><span class="sd">    After initialisation, provide a mapping interface to the plugins:</span>
+</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="sd">    &gt;&gt;&gt; print(len(registry))</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="sd">    2</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="sd">    &gt;&gt;&gt; for name in registry:</span>
+</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="sd">    ...     print(f&quot;{name}: {registry[name]}&quot;)</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="sd">    Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a><span class="sd">    Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="sd">    &gt;&gt;&gt; if &#39;Plugin1&#39; in registry:</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="sd">    ...     print(f&quot;&#39;Plugin1&#39; is in registry.&quot;)</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="sd">    &#39;Plugin1&#39; is in registry.</span>
+</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a>
+</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">namespace_package</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">base_class</span><span class="p">:</span> <span class="nb">type</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise registry.</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a>
+</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd">        Import all modules defined in the given namespace package (in any</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="sd">        distribution package currently installed in the path). Then register</span>
+</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd">        all subclasses of the given base class as plugins.</span>
+</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a>
+</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a><span class="sd">        &gt;&gt;&gt; for name in registry._plugins:</span>
+</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a><span class="sd">        ...     print(f&quot;{name}: {registry._plugins[name]}&quot;)</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a><span class="sd">        Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a><span class="sd">        Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a>        <span class="n">ns_mod</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">namespace_package</span><span class="p">)</span>
+</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a>        <span class="n">ns_path</span> <span class="o">=</span> <span class="n">ns_mod</span><span class="o">.</span><span class="n">__path__</span>
+</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a>        <span class="n">ns_name</span> <span class="o">=</span> <span class="n">ns_mod</span><span class="o">.</span><span class="vm">__name__</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>        <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">mod_name</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">pkgutil</span><span class="o">.</span><span class="n">iter_modules</span><span class="p">(</span><span class="n">ns_path</span><span class="p">):</span>
+</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a>            <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">ns_name</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">mod_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a>
+</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a>        <span class="k">def</span><span class="w"> </span><span class="nf">all_subclasses</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a>            <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a>            <span class="k">for</span> <span class="n">subcls</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">__subclasses__</span><span class="p">():</span>
+</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">subcls</span><span class="p">)</span>
+</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">all_subclasses</span><span class="p">(</span><span class="n">subcls</span><span class="p">))</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a>            <span class="k">return</span> <span class="n">result</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a>
+</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span> <span class="o">=</span> <span class="p">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="p">:</span> <span class="bp">cls</span> <span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">all_subclasses</span><span class="p">(</span><span class="n">base_class</span><span class="p">)}</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a>
+</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
+</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get number of registered plugins.</span>
+</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a>
+</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="sd">        &gt;&gt;&gt; print(registry.__len__())</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="sd">        2</span>
+</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a>        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">)</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a>
+</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get an iterator of the registered plugins.</span>
+</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a>
+</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd">        &gt;&gt;&gt; print(type(registry.__iter__()))</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd">        &lt;class &#39;dict_keyiterator&#39;&gt;</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd">        &gt;&gt;&gt; for name in registry:</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a><span class="sd">        ...     print(name)</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a><span class="sd">        Plugin1</span>
+</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="sd">        Plugin2</span>
+</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a>        <span class="k">return</span> <span class="nb">iter</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">)</span>
+</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a>
+</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">plugin_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">type</span><span class="p">:</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get a registered plugin given its name.</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a>
+</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a><span class="sd">        ...     pass</span>
+</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a><span class="sd">        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin1&#39;))</span>
+</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a><span class="sd">        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin2&#39;))</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a><span class="sd">        &gt;&gt;&gt; for name in registry:</span>
+</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a><span class="sd">        ...     print(registry[name])</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">plugin_name</span><span class="p">]</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="PluginRegistry">
+                            <input id="PluginRegistry-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">PluginRegistry</span><wbr>(<span class="base">collections.abc.Mapping</span>):
+
+                <label class="view-source-button" for="PluginRegistry-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#PluginRegistry"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="PluginRegistry-44"><a href="#PluginRegistry-44"><span class="linenos"> 44</span></a><span class="k">class</span><span class="w"> </span><span class="nc">PluginRegistry</span><span class="p">(</span><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Mapping</span><span class="p">):</span>
+</span><span id="PluginRegistry-45"><a href="#PluginRegistry-45"><span class="linenos"> 45</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Provide a registry for plugins.</span>
+</span><span id="PluginRegistry-46"><a href="#PluginRegistry-46"><span class="linenos"> 46</span></a>
+</span><span id="PluginRegistry-47"><a href="#PluginRegistry-47"><span class="linenos"> 47</span></a><span class="sd">    Initialise the registry by loading all modules in the given namespace</span>
+</span><span id="PluginRegistry-48"><a href="#PluginRegistry-48"><span class="linenos"> 48</span></a><span class="sd">    package and then registering all subclasses of the given base class as</span>
+</span><span id="PluginRegistry-49"><a href="#PluginRegistry-49"><span class="linenos"> 49</span></a><span class="sd">    plugins (only simulated here – the code for Plugin1 and Plugin2 should</span>
+</span><span id="PluginRegistry-50"><a href="#PluginRegistry-50"><span class="linenos"> 50</span></a><span class="sd">    be in modules in the given namespace package in real applications):</span>
+</span><span id="PluginRegistry-51"><a href="#PluginRegistry-51"><span class="linenos"> 51</span></a><span class="sd">    &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="PluginRegistry-52"><a href="#PluginRegistry-52"><span class="linenos"> 52</span></a><span class="sd">    ...     pass</span>
+</span><span id="PluginRegistry-53"><a href="#PluginRegistry-53"><span class="linenos"> 53</span></a><span class="sd">    &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="PluginRegistry-54"><a href="#PluginRegistry-54"><span class="linenos"> 54</span></a><span class="sd">    ...     pass</span>
+</span><span id="PluginRegistry-55"><a href="#PluginRegistry-55"><span class="linenos"> 55</span></a><span class="sd">    &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="PluginRegistry-56"><a href="#PluginRegistry-56"><span class="linenos"> 56</span></a><span class="sd">    ...     pass</span>
+</span><span id="PluginRegistry-57"><a href="#PluginRegistry-57"><span class="linenos"> 57</span></a><span class="sd">    &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="PluginRegistry-58"><a href="#PluginRegistry-58"><span class="linenos"> 58</span></a>
+</span><span id="PluginRegistry-59"><a href="#PluginRegistry-59"><span class="linenos"> 59</span></a><span class="sd">    After initialisation, provide a mapping interface to the plugins:</span>
+</span><span id="PluginRegistry-60"><a href="#PluginRegistry-60"><span class="linenos"> 60</span></a><span class="sd">    &gt;&gt;&gt; print(len(registry))</span>
+</span><span id="PluginRegistry-61"><a href="#PluginRegistry-61"><span class="linenos"> 61</span></a><span class="sd">    2</span>
+</span><span id="PluginRegistry-62"><a href="#PluginRegistry-62"><span class="linenos"> 62</span></a><span class="sd">    &gt;&gt;&gt; for name in registry:</span>
+</span><span id="PluginRegistry-63"><a href="#PluginRegistry-63"><span class="linenos"> 63</span></a><span class="sd">    ...     print(f&quot;{name}: {registry[name]}&quot;)</span>
+</span><span id="PluginRegistry-64"><a href="#PluginRegistry-64"><span class="linenos"> 64</span></a><span class="sd">    Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="PluginRegistry-65"><a href="#PluginRegistry-65"><span class="linenos"> 65</span></a><span class="sd">    Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="PluginRegistry-66"><a href="#PluginRegistry-66"><span class="linenos"> 66</span></a><span class="sd">    &gt;&gt;&gt; if &#39;Plugin1&#39; in registry:</span>
+</span><span id="PluginRegistry-67"><a href="#PluginRegistry-67"><span class="linenos"> 67</span></a><span class="sd">    ...     print(f&quot;&#39;Plugin1&#39; is in registry.&quot;)</span>
+</span><span id="PluginRegistry-68"><a href="#PluginRegistry-68"><span class="linenos"> 68</span></a><span class="sd">    &#39;Plugin1&#39; is in registry.</span>
+</span><span id="PluginRegistry-69"><a href="#PluginRegistry-69"><span class="linenos"> 69</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="PluginRegistry-70"><a href="#PluginRegistry-70"><span class="linenos"> 70</span></a>
+</span><span id="PluginRegistry-71"><a href="#PluginRegistry-71"><span class="linenos"> 71</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">namespace_package</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">base_class</span><span class="p">:</span> <span class="nb">type</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="PluginRegistry-72"><a href="#PluginRegistry-72"><span class="linenos"> 72</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise registry.</span>
+</span><span id="PluginRegistry-73"><a href="#PluginRegistry-73"><span class="linenos"> 73</span></a>
+</span><span id="PluginRegistry-74"><a href="#PluginRegistry-74"><span class="linenos"> 74</span></a><span class="sd">        Import all modules defined in the given namespace package (in any</span>
+</span><span id="PluginRegistry-75"><a href="#PluginRegistry-75"><span class="linenos"> 75</span></a><span class="sd">        distribution package currently installed in the path). Then register</span>
+</span><span id="PluginRegistry-76"><a href="#PluginRegistry-76"><span class="linenos"> 76</span></a><span class="sd">        all subclasses of the given base class as plugins.</span>
+</span><span id="PluginRegistry-77"><a href="#PluginRegistry-77"><span class="linenos"> 77</span></a>
+</span><span id="PluginRegistry-78"><a href="#PluginRegistry-78"><span class="linenos"> 78</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="PluginRegistry-79"><a href="#PluginRegistry-79"><span class="linenos"> 79</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-80"><a href="#PluginRegistry-80"><span class="linenos"> 80</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="PluginRegistry-81"><a href="#PluginRegistry-81"><span class="linenos"> 81</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-82"><a href="#PluginRegistry-82"><span class="linenos"> 82</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="PluginRegistry-83"><a href="#PluginRegistry-83"><span class="linenos"> 83</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-84"><a href="#PluginRegistry-84"><span class="linenos"> 84</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="PluginRegistry-85"><a href="#PluginRegistry-85"><span class="linenos"> 85</span></a><span class="sd">        &gt;&gt;&gt; for name in registry._plugins:</span>
+</span><span id="PluginRegistry-86"><a href="#PluginRegistry-86"><span class="linenos"> 86</span></a><span class="sd">        ...     print(f&quot;{name}: {registry._plugins[name]}&quot;)</span>
+</span><span id="PluginRegistry-87"><a href="#PluginRegistry-87"><span class="linenos"> 87</span></a><span class="sd">        Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="PluginRegistry-88"><a href="#PluginRegistry-88"><span class="linenos"> 88</span></a><span class="sd">        Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="PluginRegistry-89"><a href="#PluginRegistry-89"><span class="linenos"> 89</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="PluginRegistry-90"><a href="#PluginRegistry-90"><span class="linenos"> 90</span></a>        <span class="n">ns_mod</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">namespace_package</span><span class="p">)</span>
+</span><span id="PluginRegistry-91"><a href="#PluginRegistry-91"><span class="linenos"> 91</span></a>        <span class="n">ns_path</span> <span class="o">=</span> <span class="n">ns_mod</span><span class="o">.</span><span class="n">__path__</span>
+</span><span id="PluginRegistry-92"><a href="#PluginRegistry-92"><span class="linenos"> 92</span></a>        <span class="n">ns_name</span> <span class="o">=</span> <span class="n">ns_mod</span><span class="o">.</span><span class="vm">__name__</span>
+</span><span id="PluginRegistry-93"><a href="#PluginRegistry-93"><span class="linenos"> 93</span></a>        <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">mod_name</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">pkgutil</span><span class="o">.</span><span class="n">iter_modules</span><span class="p">(</span><span class="n">ns_path</span><span class="p">):</span>
+</span><span id="PluginRegistry-94"><a href="#PluginRegistry-94"><span class="linenos"> 94</span></a>            <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">ns_name</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">mod_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="PluginRegistry-95"><a href="#PluginRegistry-95"><span class="linenos"> 95</span></a>
+</span><span id="PluginRegistry-96"><a href="#PluginRegistry-96"><span class="linenos"> 96</span></a>        <span class="k">def</span><span class="w"> </span><span class="nf">all_subclasses</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
+</span><span id="PluginRegistry-97"><a href="#PluginRegistry-97"><span class="linenos"> 97</span></a>            <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="PluginRegistry-98"><a href="#PluginRegistry-98"><span class="linenos"> 98</span></a>            <span class="k">for</span> <span class="n">subcls</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">__subclasses__</span><span class="p">():</span>
+</span><span id="PluginRegistry-99"><a href="#PluginRegistry-99"><span class="linenos"> 99</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">subcls</span><span class="p">)</span>
+</span><span id="PluginRegistry-100"><a href="#PluginRegistry-100"><span class="linenos">100</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">all_subclasses</span><span class="p">(</span><span class="n">subcls</span><span class="p">))</span>
+</span><span id="PluginRegistry-101"><a href="#PluginRegistry-101"><span class="linenos">101</span></a>            <span class="k">return</span> <span class="n">result</span>
+</span><span id="PluginRegistry-102"><a href="#PluginRegistry-102"><span class="linenos">102</span></a>
+</span><span id="PluginRegistry-103"><a href="#PluginRegistry-103"><span class="linenos">103</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span> <span class="o">=</span> <span class="p">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="p">:</span> <span class="bp">cls</span> <span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">all_subclasses</span><span class="p">(</span><span class="n">base_class</span><span class="p">)}</span>
+</span><span id="PluginRegistry-104"><a href="#PluginRegistry-104"><span class="linenos">104</span></a>
+</span><span id="PluginRegistry-105"><a href="#PluginRegistry-105"><span class="linenos">105</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
+</span><span id="PluginRegistry-106"><a href="#PluginRegistry-106"><span class="linenos">106</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get number of registered plugins.</span>
+</span><span id="PluginRegistry-107"><a href="#PluginRegistry-107"><span class="linenos">107</span></a>
+</span><span id="PluginRegistry-108"><a href="#PluginRegistry-108"><span class="linenos">108</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="PluginRegistry-109"><a href="#PluginRegistry-109"><span class="linenos">109</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-110"><a href="#PluginRegistry-110"><span class="linenos">110</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="PluginRegistry-111"><a href="#PluginRegistry-111"><span class="linenos">111</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-112"><a href="#PluginRegistry-112"><span class="linenos">112</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="PluginRegistry-113"><a href="#PluginRegistry-113"><span class="linenos">113</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-114"><a href="#PluginRegistry-114"><span class="linenos">114</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="PluginRegistry-115"><a href="#PluginRegistry-115"><span class="linenos">115</span></a><span class="sd">        &gt;&gt;&gt; print(registry.__len__())</span>
+</span><span id="PluginRegistry-116"><a href="#PluginRegistry-116"><span class="linenos">116</span></a><span class="sd">        2</span>
+</span><span id="PluginRegistry-117"><a href="#PluginRegistry-117"><span class="linenos">117</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="PluginRegistry-118"><a href="#PluginRegistry-118"><span class="linenos">118</span></a>        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">)</span>
+</span><span id="PluginRegistry-119"><a href="#PluginRegistry-119"><span class="linenos">119</span></a>
+</span><span id="PluginRegistry-120"><a href="#PluginRegistry-120"><span class="linenos">120</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+</span><span id="PluginRegistry-121"><a href="#PluginRegistry-121"><span class="linenos">121</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get an iterator of the registered plugins.</span>
+</span><span id="PluginRegistry-122"><a href="#PluginRegistry-122"><span class="linenos">122</span></a>
+</span><span id="PluginRegistry-123"><a href="#PluginRegistry-123"><span class="linenos">123</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="PluginRegistry-124"><a href="#PluginRegistry-124"><span class="linenos">124</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-125"><a href="#PluginRegistry-125"><span class="linenos">125</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="PluginRegistry-126"><a href="#PluginRegistry-126"><span class="linenos">126</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-127"><a href="#PluginRegistry-127"><span class="linenos">127</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="PluginRegistry-128"><a href="#PluginRegistry-128"><span class="linenos">128</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-129"><a href="#PluginRegistry-129"><span class="linenos">129</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="PluginRegistry-130"><a href="#PluginRegistry-130"><span class="linenos">130</span></a><span class="sd">        &gt;&gt;&gt; print(type(registry.__iter__()))</span>
+</span><span id="PluginRegistry-131"><a href="#PluginRegistry-131"><span class="linenos">131</span></a><span class="sd">        &lt;class &#39;dict_keyiterator&#39;&gt;</span>
+</span><span id="PluginRegistry-132"><a href="#PluginRegistry-132"><span class="linenos">132</span></a><span class="sd">        &gt;&gt;&gt; for name in registry:</span>
+</span><span id="PluginRegistry-133"><a href="#PluginRegistry-133"><span class="linenos">133</span></a><span class="sd">        ...     print(name)</span>
+</span><span id="PluginRegistry-134"><a href="#PluginRegistry-134"><span class="linenos">134</span></a><span class="sd">        Plugin1</span>
+</span><span id="PluginRegistry-135"><a href="#PluginRegistry-135"><span class="linenos">135</span></a><span class="sd">        Plugin2</span>
+</span><span id="PluginRegistry-136"><a href="#PluginRegistry-136"><span class="linenos">136</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="PluginRegistry-137"><a href="#PluginRegistry-137"><span class="linenos">137</span></a>        <span class="k">return</span> <span class="nb">iter</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">)</span>
+</span><span id="PluginRegistry-138"><a href="#PluginRegistry-138"><span class="linenos">138</span></a>
+</span><span id="PluginRegistry-139"><a href="#PluginRegistry-139"><span class="linenos">139</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">plugin_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">type</span><span class="p">:</span>
+</span><span id="PluginRegistry-140"><a href="#PluginRegistry-140"><span class="linenos">140</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Get a registered plugin given its name.</span>
+</span><span id="PluginRegistry-141"><a href="#PluginRegistry-141"><span class="linenos">141</span></a>
+</span><span id="PluginRegistry-142"><a href="#PluginRegistry-142"><span class="linenos">142</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="PluginRegistry-143"><a href="#PluginRegistry-143"><span class="linenos">143</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-144"><a href="#PluginRegistry-144"><span class="linenos">144</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="PluginRegistry-145"><a href="#PluginRegistry-145"><span class="linenos">145</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-146"><a href="#PluginRegistry-146"><span class="linenos">146</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="PluginRegistry-147"><a href="#PluginRegistry-147"><span class="linenos">147</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry-148"><a href="#PluginRegistry-148"><span class="linenos">148</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="PluginRegistry-149"><a href="#PluginRegistry-149"><span class="linenos">149</span></a><span class="sd">        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin1&#39;))</span>
+</span><span id="PluginRegistry-150"><a href="#PluginRegistry-150"><span class="linenos">150</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="PluginRegistry-151"><a href="#PluginRegistry-151"><span class="linenos">151</span></a><span class="sd">        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin2&#39;))</span>
+</span><span id="PluginRegistry-152"><a href="#PluginRegistry-152"><span class="linenos">152</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="PluginRegistry-153"><a href="#PluginRegistry-153"><span class="linenos">153</span></a><span class="sd">        &gt;&gt;&gt; for name in registry:</span>
+</span><span id="PluginRegistry-154"><a href="#PluginRegistry-154"><span class="linenos">154</span></a><span class="sd">        ...     print(registry[name])</span>
+</span><span id="PluginRegistry-155"><a href="#PluginRegistry-155"><span class="linenos">155</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="PluginRegistry-156"><a href="#PluginRegistry-156"><span class="linenos">156</span></a><span class="sd">        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="PluginRegistry-157"><a href="#PluginRegistry-157"><span class="linenos">157</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="PluginRegistry-158"><a href="#PluginRegistry-158"><span class="linenos">158</span></a>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">plugin_name</span><span class="p">]</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Provide a registry for plugins.</p>
+
+<p>Initialise the registry by loading all modules in the given namespace
+package and then registering all subclasses of the given base class as
+plugins (only simulated here – the code for Plugin1 and Plugin2 should
+be in modules in the given namespace package in real applications):</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">BasePlugin</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">Plugin1</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">Plugin2</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">registry</span> <span class="o">=</span> <span class="n">PluginRegistry</span><span class="p">(</span><span class="s1">&#39;importlib&#39;</span><span class="p">,</span> <span class="n">BasePlugin</span><span class="p">)</span>
+</code></pre>
+</div>
+
+<p>After initialisation, provide a mapping interface to the plugins:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">registry</span><span class="p">))</span>
+<span class="go">2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">registry</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">registry</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+<span class="go">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">if</span> <span class="s1">&#39;Plugin1&#39;</span> <span class="ow">in</span> <span class="n">registry</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;&#39;Plugin1&#39; is in registry.&quot;</span><span class="p">)</span>
+<span class="go">&#39;Plugin1&#39; is in registry.</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="PluginRegistry.__init__" class="classattr">
+                                        <input id="PluginRegistry.__init__-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="name">PluginRegistry</span><span class="signature pdoc-code condensed">(<span class="param"><span class="n">namespace_package</span><span class="p">:</span> <span class="nb">str</span>, </span><span class="param"><span class="n">base_class</span><span class="p">:</span> <span class="nb">type</span></span>)</span>
+
+                <label class="view-source-button" for="PluginRegistry.__init__-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#PluginRegistry.__init__"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="PluginRegistry.__init__-71"><a href="#PluginRegistry.__init__-71"><span class="linenos"> 71</span></a>    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">namespace_package</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">base_class</span><span class="p">:</span> <span class="nb">type</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="PluginRegistry.__init__-72"><a href="#PluginRegistry.__init__-72"><span class="linenos"> 72</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Initialise registry.</span>
+</span><span id="PluginRegistry.__init__-73"><a href="#PluginRegistry.__init__-73"><span class="linenos"> 73</span></a>
+</span><span id="PluginRegistry.__init__-74"><a href="#PluginRegistry.__init__-74"><span class="linenos"> 74</span></a><span class="sd">        Import all modules defined in the given namespace package (in any</span>
+</span><span id="PluginRegistry.__init__-75"><a href="#PluginRegistry.__init__-75"><span class="linenos"> 75</span></a><span class="sd">        distribution package currently installed in the path). Then register</span>
+</span><span id="PluginRegistry.__init__-76"><a href="#PluginRegistry.__init__-76"><span class="linenos"> 76</span></a><span class="sd">        all subclasses of the given base class as plugins.</span>
+</span><span id="PluginRegistry.__init__-77"><a href="#PluginRegistry.__init__-77"><span class="linenos"> 77</span></a>
+</span><span id="PluginRegistry.__init__-78"><a href="#PluginRegistry.__init__-78"><span class="linenos"> 78</span></a><span class="sd">        &gt;&gt;&gt; class BasePlugin:</span>
+</span><span id="PluginRegistry.__init__-79"><a href="#PluginRegistry.__init__-79"><span class="linenos"> 79</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry.__init__-80"><a href="#PluginRegistry.__init__-80"><span class="linenos"> 80</span></a><span class="sd">        &gt;&gt;&gt; class Plugin1(BasePlugin):</span>
+</span><span id="PluginRegistry.__init__-81"><a href="#PluginRegistry.__init__-81"><span class="linenos"> 81</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry.__init__-82"><a href="#PluginRegistry.__init__-82"><span class="linenos"> 82</span></a><span class="sd">        &gt;&gt;&gt; class Plugin2(BasePlugin):</span>
+</span><span id="PluginRegistry.__init__-83"><a href="#PluginRegistry.__init__-83"><span class="linenos"> 83</span></a><span class="sd">        ...     pass</span>
+</span><span id="PluginRegistry.__init__-84"><a href="#PluginRegistry.__init__-84"><span class="linenos"> 84</span></a><span class="sd">        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)</span>
+</span><span id="PluginRegistry.__init__-85"><a href="#PluginRegistry.__init__-85"><span class="linenos"> 85</span></a><span class="sd">        &gt;&gt;&gt; for name in registry._plugins:</span>
+</span><span id="PluginRegistry.__init__-86"><a href="#PluginRegistry.__init__-86"><span class="linenos"> 86</span></a><span class="sd">        ...     print(f&quot;{name}: {registry._plugins[name]}&quot;)</span>
+</span><span id="PluginRegistry.__init__-87"><a href="#PluginRegistry.__init__-87"><span class="linenos"> 87</span></a><span class="sd">        Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+</span><span id="PluginRegistry.__init__-88"><a href="#PluginRegistry.__init__-88"><span class="linenos"> 88</span></a><span class="sd">        Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</span><span id="PluginRegistry.__init__-89"><a href="#PluginRegistry.__init__-89"><span class="linenos"> 89</span></a><span class="sd">        &quot;&quot;&quot;</span>
+</span><span id="PluginRegistry.__init__-90"><a href="#PluginRegistry.__init__-90"><span class="linenos"> 90</span></a>        <span class="n">ns_mod</span> <span class="o">=</span> <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="n">namespace_package</span><span class="p">)</span>
+</span><span id="PluginRegistry.__init__-91"><a href="#PluginRegistry.__init__-91"><span class="linenos"> 91</span></a>        <span class="n">ns_path</span> <span class="o">=</span> <span class="n">ns_mod</span><span class="o">.</span><span class="n">__path__</span>
+</span><span id="PluginRegistry.__init__-92"><a href="#PluginRegistry.__init__-92"><span class="linenos"> 92</span></a>        <span class="n">ns_name</span> <span class="o">=</span> <span class="n">ns_mod</span><span class="o">.</span><span class="vm">__name__</span>
+</span><span id="PluginRegistry.__init__-93"><a href="#PluginRegistry.__init__-93"><span class="linenos"> 93</span></a>        <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">mod_name</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">pkgutil</span><span class="o">.</span><span class="n">iter_modules</span><span class="p">(</span><span class="n">ns_path</span><span class="p">):</span>
+</span><span id="PluginRegistry.__init__-94"><a href="#PluginRegistry.__init__-94"><span class="linenos"> 94</span></a>            <span class="n">importlib</span><span class="o">.</span><span class="n">import_module</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">ns_name</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">mod_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="PluginRegistry.__init__-95"><a href="#PluginRegistry.__init__-95"><span class="linenos"> 95</span></a>
+</span><span id="PluginRegistry.__init__-96"><a href="#PluginRegistry.__init__-96"><span class="linenos"> 96</span></a>        <span class="k">def</span><span class="w"> </span><span class="nf">all_subclasses</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
+</span><span id="PluginRegistry.__init__-97"><a href="#PluginRegistry.__init__-97"><span class="linenos"> 97</span></a>            <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="PluginRegistry.__init__-98"><a href="#PluginRegistry.__init__-98"><span class="linenos"> 98</span></a>            <span class="k">for</span> <span class="n">subcls</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">__subclasses__</span><span class="p">():</span>
+</span><span id="PluginRegistry.__init__-99"><a href="#PluginRegistry.__init__-99"><span class="linenos"> 99</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">subcls</span><span class="p">)</span>
+</span><span id="PluginRegistry.__init__-100"><a href="#PluginRegistry.__init__-100"><span class="linenos">100</span></a>                <span class="n">result</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">all_subclasses</span><span class="p">(</span><span class="n">subcls</span><span class="p">))</span>
+</span><span id="PluginRegistry.__init__-101"><a href="#PluginRegistry.__init__-101"><span class="linenos">101</span></a>            <span class="k">return</span> <span class="n">result</span>
+</span><span id="PluginRegistry.__init__-102"><a href="#PluginRegistry.__init__-102"><span class="linenos">102</span></a>
+</span><span id="PluginRegistry.__init__-103"><a href="#PluginRegistry.__init__-103"><span class="linenos">103</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_plugins</span> <span class="o">=</span> <span class="p">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="p">:</span> <span class="bp">cls</span> <span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">all_subclasses</span><span class="p">(</span><span class="n">base_class</span><span class="p">)}</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Initialise registry.</p>
+
+<p>Import all modules defined in the given namespace package (in any
+distribution package currently installed in the path). Then register
+all subclasses of the given base class as plugins.</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">BasePlugin</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">Plugin1</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span><span class="w"> </span><span class="nc">Plugin2</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+<span class="gp">... </span>    <span class="k">pass</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">registry</span> <span class="o">=</span> <span class="n">PluginRegistry</span><span class="p">(</span><span class="s1">&#39;importlib&#39;</span><span class="p">,</span> <span class="n">BasePlugin</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">registry</span><span class="o">.</span><span class="n">_plugins</span><span class="p">:</span>
+<span class="gp">... </span>    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">registry</span><span class="o">.</span><span class="n">_plugins</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+<span class="go">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>
+<span class="go">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>
+</code></pre>
+</div>
+</div>
+
+
+                            </div>
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "../search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `../${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi_plugins.html b/doc/api/controlpi_plugins.html
new file mode 100644 (file)
index 0000000..6e2e933
--- /dev/null
@@ -0,0 +1,241 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi_plugins API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="index.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;
+                Module Index
+            </a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+            <h2>Submodules</h2>
+            <ul>
+                    <li><a href="controlpi_plugins/state.html">state</a></li>
+                    <li><a href="controlpi_plugins/util.html">util</a></li>
+                    <li><a href="controlpi_plugins/wait.html">wait</a></li>
+            </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+controlpi_plugins    </h1>
+
+                
+                
+                
+                
+            </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi_plugins/state.html b/doc/api/controlpi_plugins/state.html
new file mode 100644 (file)
index 0000000..9ffcff8
--- /dev/null
@@ -0,0 +1,3256 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi_plugins.state API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="../controlpi_plugins.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;controlpi_plugins</a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="class" href="#State">State</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#State.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#State.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#State.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#StateAlias">StateAlias</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#StateAlias.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#StateAlias.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#StateAlias.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#AndState">AndState</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#AndState.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#AndState.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#AndState.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#OrState">OrState</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#OrState.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#OrState.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#OrState.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#AndSet">AndSet</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#AndSet.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#AndSet.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#AndSet.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#OrSet">OrSet</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#OrSet.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#OrSet.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#OrSet.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+<a href="./../controlpi_plugins.html">controlpi_plugins</a><wbr>.state    </h1>
+
+                        <div class="docstring"><p>Provide state plugins for all kinds of systems.</p>
+
+<ul>
+<li>State represents a Boolean state.</li>
+<li>StateAlias translates to another state-like client.</li>
+<li>AndState combines several state-like clients by conjunction.</li>
+<li>OrState combines several state-like clients by disjunction.</li>
+<li>AndSet sets a state due to a conjunction of other state-like clients.</li>
+<li>OrSet sets a state due to a disjunction of other state-like clients.</li>
+</ul>
+
+<p>All these plugins use the following conventions:</p>
+
+<ul>
+<li>If their state changes they send a message containing "event": "changed"
+and "state": NEW STATE.</li>
+<li>If their state is reported due to a message, but did not change they send
+a message containing just "state": CURRENT STATE.</li>
+<li>If they receive a message containing "target": NAME and
+"command": "get state" they report their current state.</li>
+<li>If State (or any other settable state using these conventions) receives
+a message containing "target": NAME, "command": "set state" and
+"new state": STATE TO SET it changes the state accordingly. If this
+was really a change the corresponding event is sent. If it was already in
+this state a report message without "event": "changed" is sent.</li>
+<li>StateAlias can alias any message bus client using these conventions, not
+just State instances. It translates all messages described here in both
+directions.</li>
+<li>AndState and OrState instances cannot be set.</li>
+<li>AndState and OrState can combine any message bus clients using these
+conventions, not just State instances. They only react to messages
+containing "state" information.</li>
+</ul>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 2&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 3&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 4&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;StateAlias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                         <span class="s2">&quot;alias for&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test AndState&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;AndState&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                       <span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">]},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test OrState&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;OrState&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                      <span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">]},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test AndSet&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                     <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">],</span>
+<span class="gp">... </span>                     <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 3&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test OrSet&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;OrSet&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                     <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">],</span>
+<span class="gp">... </span>                     <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 4&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test AndState&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test OrState&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span> <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span> <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span> <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;, &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;, &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 4&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 4&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</code></pre>
+</div>
+</div>
+
+                        <input id="mod-state-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-state-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">  1</span></a><span class="sd">&quot;&quot;&quot;Provide state plugins for all kinds of systems.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">  2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">  3</span></a><span class="sd">- State represents a Boolean state.</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">  4</span></a><span class="sd">- StateAlias translates to another state-like client.</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">  5</span></a><span class="sd">- AndState combines several state-like clients by conjunction.</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">  6</span></a><span class="sd">- OrState combines several state-like clients by disjunction.</span>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">  7</span></a><span class="sd">- AndSet sets a state due to a conjunction of other state-like clients.</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">  8</span></a><span class="sd">- OrSet sets a state due to a disjunction of other state-like clients.</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">  9</span></a>
+</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="sd">All these plugins use the following conventions:</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a>
+</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a><span class="sd">- If their state changes they send a message containing &quot;event&quot;: &quot;changed&quot;</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a><span class="sd">  and &quot;state&quot;: NEW STATE.</span>
+</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="sd">- If their state is reported due to a message, but did not change they send</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a><span class="sd">  a message containing just &quot;state&quot;: CURRENT STATE.</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="sd">- If they receive a message containing &quot;target&quot;: NAME and</span>
+</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="sd">  &quot;command&quot;: &quot;get state&quot; they report their current state.</span>
+</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="sd">- If State (or any other settable state using these conventions) receives</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a><span class="sd">  a message containing &quot;target&quot;: NAME, &quot;command&quot;: &quot;set state&quot; and</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a><span class="sd">  &quot;new state&quot;: STATE TO SET it changes the state accordingly. If this</span>
+</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a><span class="sd">  was really a change the corresponding event is sent. If it was already in</span>
+</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="sd">  this state a report message without &quot;event&quot;: &quot;changed&quot; is sent.</span>
+</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a><span class="sd">- StateAlias can alias any message bus client using these conventions, not</span>
+</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a><span class="sd">  just State instances. It translates all messages described here in both</span>
+</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a><span class="sd">  directions.</span>
+</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a><span class="sd">- AndState and OrState instances cannot be set.</span>
+</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="sd">- AndState and OrState can combine any message bus clients using these</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a><span class="sd">  conventions, not just State instances. They only react to messages</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="sd">  containing &quot;state&quot; information.</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a>
+</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="sd">&gt;&gt;&gt; import asyncio</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a><span class="sd">&gt;&gt;&gt; import controlpi</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a><span class="sd">&gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a><span class="sd">...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a><span class="sd">...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a><span class="sd">...      &quot;Test State 3&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a><span class="sd">...      &quot;Test State 4&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a><span class="sd">...      &quot;Test StateAlias&quot;: {&quot;plugin&quot;: &quot;StateAlias&quot;,</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a><span class="sd">...                          &quot;alias for&quot;: &quot;Test State 2&quot;},</span>
+</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a><span class="sd">...      &quot;Test AndState&quot;: {&quot;plugin&quot;: &quot;AndState&quot;,</span>
+</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a><span class="sd">...                        &quot;states&quot;: [&quot;Test State&quot;, &quot;Test StateAlias&quot;]},</span>
+</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a><span class="sd">...      &quot;Test OrState&quot;: {&quot;plugin&quot;: &quot;OrState&quot;,</span>
+</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a><span class="sd">...                       &quot;states&quot;: [&quot;Test State&quot;, &quot;Test StateAlias&quot;]},</span>
+</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="sd">...      &quot;Test AndSet&quot;: {&quot;plugin&quot;: &quot;AndSet&quot;,</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a><span class="sd">...                      &quot;input states&quot;: [&quot;Test State&quot;, &quot;Test StateAlias&quot;],</span>
+</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="sd">...                      &quot;output state&quot;: &quot;Test State 3&quot;},</span>
+</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="sd">...      &quot;Test OrSet&quot;: {&quot;plugin&quot;: &quot;OrSet&quot;,</span>
+</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a><span class="sd">...                      &quot;input states&quot;: [&quot;Test State&quot;, &quot;Test StateAlias&quot;],</span>
+</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="sd">...                      &quot;output state&quot;: &quot;Test State 4&quot;}},</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="sd">...     [{&quot;target&quot;: &quot;Test AndState&quot;,</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a><span class="sd">...       &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a><span class="sd">...      {&quot;target&quot;: &quot;Test OrState&quot;,</span>
+</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a><span class="sd">...       &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a><span class="sd">...      {&quot;target&quot;: &quot;Test State&quot;,</span>
+</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a><span class="sd">...       &quot;command&quot;: &quot;set state&quot;, &quot;new state&quot;: True},</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a><span class="sd">...      {&quot;target&quot;: &quot;Test StateAlias&quot;,</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a><span class="sd">...       &quot;command&quot;: &quot;set state&quot;, &quot;new state&quot;: True},</span>
+</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a><span class="sd">...      {&quot;target&quot;: &quot;Test State&quot;,</span>
+</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="sd">...       &quot;command&quot;: &quot;set state&quot;, &quot;new state&quot;: False}]))</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="sd">... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;, &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;, &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="sd">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a><span class="sd">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a><span class="sd">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="sd">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 4&#39;,</span>
+</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test State 4&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a>
+</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi</span><span class="w"> </span><span class="kn">import</span> <span class="n">BasePlugin</span><span class="p">,</span> <span class="n">Message</span><span class="p">,</span> <span class="n">MessageTemplate</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a>
+</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a>
+</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a>
+</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a><span class="k">class</span><span class="w"> </span><span class="nc">State</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Provide a Boolean state.</span>
+</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a>
+</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a><span class="sd">    The state of a State plugin instance can be queried with the &quot;get state&quot;</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a><span class="sd">    command and set with the &quot;set state&quot; command to the new state given by</span>
+</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a><span class="sd">    the &quot;new state&quot; key:</span>
+</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a><span class="sd">    ...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;}},</span>
+</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;}]))</span>
+</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a>
+</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for State plugin configuration.</span>
+</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a>
+</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd">    There are no required or optional configuration keys.</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a>
+</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a>            <span class="s2">&quot;State&quot;</span><span class="p">,</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a>            <span class="p">[</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a>                <span class="p">),</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a>            <span class="p">],</span>
+</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a>            <span class="p">[</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a>                <span class="p">(</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a>                    <span class="p">[</span>
+</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a>                            <span class="p">{</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a>                            <span class="p">}</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a>                        <span class="p">)</span>
+</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a>                    <span class="p">],</span>
+</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a>                <span class="p">),</span>
+</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a>                <span class="p">(</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a>                    <span class="p">[</span>
+</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a>                            <span class="p">{</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a>                                <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a>                            <span class="p">}</span>
+</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a>                        <span class="p">)</span>
+</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a>                    <span class="p">],</span>
+</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_state</span><span class="p">,</span>
+</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a>                <span class="p">),</span>
+</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a>            <span class="p">],</span>
+</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a>        <span class="p">)</span>
+</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a>
+</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a>
+</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_set_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">]:</span>
+</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a>            <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">]</span>
+</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">,</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">})</span>
+</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a>            <span class="p">)</span>
+</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a>        <span class="k">else</span><span class="p">:</span>
+</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a>
+</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a>        <span class="k">pass</span>
+</span><span id="L-181"><a href="#L-181"><span class="linenos">181</span></a>
+</span><span id="L-182"><a href="#L-182"><span class="linenos">182</span></a>
+</span><span id="L-183"><a href="#L-183"><span class="linenos">183</span></a><span class="k">class</span><span class="w"> </span><span class="nc">StateAlias</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-184"><a href="#L-184"><span class="linenos">184</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define an alias for another state.</span>
+</span><span id="L-185"><a href="#L-185"><span class="linenos">185</span></a>
+</span><span id="L-186"><a href="#L-186"><span class="linenos">186</span></a><span class="sd">    The &quot;alias for&quot; configuration key gets the name for the other state that</span>
+</span><span id="L-187"><a href="#L-187"><span class="linenos">187</span></a><span class="sd">    is aliased by the StateAlias plugin instance.</span>
+</span><span id="L-188"><a href="#L-188"><span class="linenos">188</span></a>
+</span><span id="L-189"><a href="#L-189"><span class="linenos">189</span></a><span class="sd">    The &quot;get state&quot; and &quot;set state&quot; commands are forwarded to and the</span>
+</span><span id="L-190"><a href="#L-190"><span class="linenos">190</span></a><span class="sd">    &quot;changed&quot; events and &quot;state&quot; messages are forwarded from this other</span>
+</span><span id="L-191"><a href="#L-191"><span class="linenos">191</span></a><span class="sd">    state:</span>
+</span><span id="L-192"><a href="#L-192"><span class="linenos">192</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-193"><a href="#L-193"><span class="linenos">193</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-194"><a href="#L-194"><span class="linenos">194</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-195"><a href="#L-195"><span class="linenos">195</span></a><span class="sd">    ...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-196"><a href="#L-196"><span class="linenos">196</span></a><span class="sd">    ...      &quot;Test StateAlias&quot;: {&quot;plugin&quot;: &quot;StateAlias&quot;,</span>
+</span><span id="L-197"><a href="#L-197"><span class="linenos">197</span></a><span class="sd">    ...                          &quot;alias for&quot;: &quot;Test State&quot;}},</span>
+</span><span id="L-198"><a href="#L-198"><span class="linenos">198</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-199"><a href="#L-199"><span class="linenos">199</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test StateAlias&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-200"><a href="#L-200"><span class="linenos">200</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-201"><a href="#L-201"><span class="linenos">201</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-202"><a href="#L-202"><span class="linenos">202</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-203"><a href="#L-203"><span class="linenos">203</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test StateAlias&quot;, &quot;command&quot;: &quot;get state&quot;}]))</span>
+</span><span id="L-204"><a href="#L-204"><span class="linenos">204</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-205"><a href="#L-205"><span class="linenos">205</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-206"><a href="#L-206"><span class="linenos">206</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-207"><a href="#L-207"><span class="linenos">207</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-208"><a href="#L-208"><span class="linenos">208</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+</span><span id="L-209"><a href="#L-209"><span class="linenos">209</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-210"><a href="#L-210"><span class="linenos">210</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-211"><a href="#L-211"><span class="linenos">211</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-212"><a href="#L-212"><span class="linenos">212</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-213"><a href="#L-213"><span class="linenos">213</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-214"><a href="#L-214"><span class="linenos">214</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-215"><a href="#L-215"><span class="linenos">215</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-216"><a href="#L-216"><span class="linenos">216</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+</span><span id="L-217"><a href="#L-217"><span class="linenos">217</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-218"><a href="#L-218"><span class="linenos">218</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-219"><a href="#L-219"><span class="linenos">219</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-220"><a href="#L-220"><span class="linenos">220</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="L-221"><a href="#L-221"><span class="linenos">221</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-222"><a href="#L-222"><span class="linenos">222</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-223"><a href="#L-223"><span class="linenos">223</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-224"><a href="#L-224"><span class="linenos">224</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-225"><a href="#L-225"><span class="linenos">225</span></a>
+</span><span id="L-226"><a href="#L-226"><span class="linenos">226</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-227"><a href="#L-227"><span class="linenos">227</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;alias for&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}},</span>
+</span><span id="L-228"><a href="#L-228"><span class="linenos">228</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">],</span>
+</span><span id="L-229"><a href="#L-229"><span class="linenos">229</span></a>    <span class="p">}</span>
+</span><span id="L-230"><a href="#L-230"><span class="linenos">230</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for StateAlias plugin configuration.</span>
+</span><span id="L-231"><a href="#L-231"><span class="linenos">231</span></a>
+</span><span id="L-232"><a href="#L-232"><span class="linenos">232</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-233"><a href="#L-233"><span class="linenos">233</span></a>
+</span><span id="L-234"><a href="#L-234"><span class="linenos">234</span></a><span class="sd">    - &#39;alias for&#39;: name of aliased state.</span>
+</span><span id="L-235"><a href="#L-235"><span class="linenos">235</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-236"><a href="#L-236"><span class="linenos">236</span></a>
+</span><span id="L-237"><a href="#L-237"><span class="linenos">237</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-238"><a href="#L-238"><span class="linenos">238</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-239"><a href="#L-239"><span class="linenos">239</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-240"><a href="#L-240"><span class="linenos">240</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-241"><a href="#L-241"><span class="linenos">241</span></a>            <span class="s2">&quot;StateAlias&quot;</span><span class="p">,</span>
+</span><span id="L-242"><a href="#L-242"><span class="linenos">242</span></a>            <span class="p">[</span>
+</span><span id="L-243"><a href="#L-243"><span class="linenos">243</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-244"><a href="#L-244"><span class="linenos">244</span></a>                    <span class="p">{</span>
+</span><span id="L-245"><a href="#L-245"><span class="linenos">245</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="L-246"><a href="#L-246"><span class="linenos">246</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-247"><a href="#L-247"><span class="linenos">247</span></a>                    <span class="p">}</span>
+</span><span id="L-248"><a href="#L-248"><span class="linenos">248</span></a>                <span class="p">),</span>
+</span><span id="L-249"><a href="#L-249"><span class="linenos">249</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-250"><a href="#L-250"><span class="linenos">250</span></a>                    <span class="p">{</span>
+</span><span id="L-251"><a href="#L-251"><span class="linenos">251</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="L-252"><a href="#L-252"><span class="linenos">252</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="L-253"><a href="#L-253"><span class="linenos">253</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="L-254"><a href="#L-254"><span class="linenos">254</span></a>                    <span class="p">}</span>
+</span><span id="L-255"><a href="#L-255"><span class="linenos">255</span></a>                <span class="p">),</span>
+</span><span id="L-256"><a href="#L-256"><span class="linenos">256</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-257"><a href="#L-257"><span class="linenos">257</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-258"><a href="#L-258"><span class="linenos">258</span></a>                <span class="p">),</span>
+</span><span id="L-259"><a href="#L-259"><span class="linenos">259</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="L-260"><a href="#L-260"><span class="linenos">260</span></a>            <span class="p">],</span>
+</span><span id="L-261"><a href="#L-261"><span class="linenos">261</span></a>            <span class="p">[</span>
+</span><span id="L-262"><a href="#L-262"><span class="linenos">262</span></a>                <span class="p">(</span>
+</span><span id="L-263"><a href="#L-263"><span class="linenos">263</span></a>                    <span class="p">[</span>
+</span><span id="L-264"><a href="#L-264"><span class="linenos">264</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-265"><a href="#L-265"><span class="linenos">265</span></a>                            <span class="p">{</span>
+</span><span id="L-266"><a href="#L-266"><span class="linenos">266</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-267"><a href="#L-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-268"><a href="#L-268"><span class="linenos">268</span></a>                            <span class="p">}</span>
+</span><span id="L-269"><a href="#L-269"><span class="linenos">269</span></a>                        <span class="p">)</span>
+</span><span id="L-270"><a href="#L-270"><span class="linenos">270</span></a>                    <span class="p">],</span>
+</span><span id="L-271"><a href="#L-271"><span class="linenos">271</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="L-272"><a href="#L-272"><span class="linenos">272</span></a>                <span class="p">),</span>
+</span><span id="L-273"><a href="#L-273"><span class="linenos">273</span></a>                <span class="p">(</span>
+</span><span id="L-274"><a href="#L-274"><span class="linenos">274</span></a>                    <span class="p">[</span>
+</span><span id="L-275"><a href="#L-275"><span class="linenos">275</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-276"><a href="#L-276"><span class="linenos">276</span></a>                            <span class="p">{</span>
+</span><span id="L-277"><a href="#L-277"><span class="linenos">277</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-278"><a href="#L-278"><span class="linenos">278</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="L-279"><a href="#L-279"><span class="linenos">279</span></a>                                <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="L-280"><a href="#L-280"><span class="linenos">280</span></a>                            <span class="p">}</span>
+</span><span id="L-281"><a href="#L-281"><span class="linenos">281</span></a>                        <span class="p">)</span>
+</span><span id="L-282"><a href="#L-282"><span class="linenos">282</span></a>                    <span class="p">],</span>
+</span><span id="L-283"><a href="#L-283"><span class="linenos">283</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_state</span><span class="p">,</span>
+</span><span id="L-284"><a href="#L-284"><span class="linenos">284</span></a>                <span class="p">),</span>
+</span><span id="L-285"><a href="#L-285"><span class="linenos">285</span></a>                <span class="p">(</span>
+</span><span id="L-286"><a href="#L-286"><span class="linenos">286</span></a>                    <span class="p">[</span>
+</span><span id="L-287"><a href="#L-287"><span class="linenos">287</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-288"><a href="#L-288"><span class="linenos">288</span></a>                            <span class="p">{</span>
+</span><span id="L-289"><a href="#L-289"><span class="linenos">289</span></a>                                <span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="L-290"><a href="#L-290"><span class="linenos">290</span></a>                                <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="L-291"><a href="#L-291"><span class="linenos">291</span></a>                            <span class="p">}</span>
+</span><span id="L-292"><a href="#L-292"><span class="linenos">292</span></a>                        <span class="p">)</span>
+</span><span id="L-293"><a href="#L-293"><span class="linenos">293</span></a>                    <span class="p">],</span>
+</span><span id="L-294"><a href="#L-294"><span class="linenos">294</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">,</span>
+</span><span id="L-295"><a href="#L-295"><span class="linenos">295</span></a>                <span class="p">),</span>
+</span><span id="L-296"><a href="#L-296"><span class="linenos">296</span></a>            <span class="p">],</span>
+</span><span id="L-297"><a href="#L-297"><span class="linenos">297</span></a>        <span class="p">)</span>
+</span><span id="L-298"><a href="#L-298"><span class="linenos">298</span></a>
+</span><span id="L-299"><a href="#L-299"><span class="linenos">299</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-300"><a href="#L-300"><span class="linenos">300</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-301"><a href="#L-301"><span class="linenos">301</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-302"><a href="#L-302"><span class="linenos">302</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">],</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">}</span>
+</span><span id="L-303"><a href="#L-303"><span class="linenos">303</span></a>            <span class="p">)</span>
+</span><span id="L-304"><a href="#L-304"><span class="linenos">304</span></a>        <span class="p">)</span>
+</span><span id="L-305"><a href="#L-305"><span class="linenos">305</span></a>
+</span><span id="L-306"><a href="#L-306"><span class="linenos">306</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_set_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-307"><a href="#L-307"><span class="linenos">307</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-308"><a href="#L-308"><span class="linenos">308</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-309"><a href="#L-309"><span class="linenos">309</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-310"><a href="#L-310"><span class="linenos">310</span></a>                <span class="p">{</span>
+</span><span id="L-311"><a href="#L-311"><span class="linenos">311</span></a>                    <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">],</span>
+</span><span id="L-312"><a href="#L-312"><span class="linenos">312</span></a>                    <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="L-313"><a href="#L-313"><span class="linenos">313</span></a>                    <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">],</span>
+</span><span id="L-314"><a href="#L-314"><span class="linenos">314</span></a>                <span class="p">},</span>
+</span><span id="L-315"><a href="#L-315"><span class="linenos">315</span></a>            <span class="p">)</span>
+</span><span id="L-316"><a href="#L-316"><span class="linenos">316</span></a>        <span class="p">)</span>
+</span><span id="L-317"><a href="#L-317"><span class="linenos">317</span></a>
+</span><span id="L-318"><a href="#L-318"><span class="linenos">318</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_translate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-319"><a href="#L-319"><span class="linenos">319</span></a>        <span class="n">alias_message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+</span><span id="L-320"><a href="#L-320"><span class="linenos">320</span></a>        <span class="k">if</span> <span class="s2">&quot;event&quot;</span> <span class="ow">in</span> <span class="n">message</span> <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;changed&quot;</span><span class="p">:</span>
+</span><span id="L-321"><a href="#L-321"><span class="linenos">321</span></a>            <span class="n">alias_message</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;changed&quot;</span>
+</span><span id="L-322"><a href="#L-322"><span class="linenos">322</span></a>        <span class="n">alias_message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="L-323"><a href="#L-323"><span class="linenos">323</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">alias_message</span><span class="p">)</span>
+</span><span id="L-324"><a href="#L-324"><span class="linenos">324</span></a>
+</span><span id="L-325"><a href="#L-325"><span class="linenos">325</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-326"><a href="#L-326"><span class="linenos">326</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-327"><a href="#L-327"><span class="linenos">327</span></a>        <span class="k">pass</span>
+</span><span id="L-328"><a href="#L-328"><span class="linenos">328</span></a>
+</span><span id="L-329"><a href="#L-329"><span class="linenos">329</span></a>
+</span><span id="L-330"><a href="#L-330"><span class="linenos">330</span></a><span class="k">class</span><span class="w"> </span><span class="nc">AndState</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-331"><a href="#L-331"><span class="linenos">331</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define conjunction of states.</span>
+</span><span id="L-332"><a href="#L-332"><span class="linenos">332</span></a>
+</span><span id="L-333"><a href="#L-333"><span class="linenos">333</span></a><span class="sd">    The &quot;states&quot; configuration key gets an array of states to be combined.</span>
+</span><span id="L-334"><a href="#L-334"><span class="linenos">334</span></a><span class="sd">    An AndState plugin client reacts to &quot;get state&quot; commands and sends</span>
+</span><span id="L-335"><a href="#L-335"><span class="linenos">335</span></a><span class="sd">    &quot;changed&quot; events when a change in one of the combined states leads to</span>
+</span><span id="L-336"><a href="#L-336"><span class="linenos">336</span></a><span class="sd">    a change for the conjunction:</span>
+</span><span id="L-337"><a href="#L-337"><span class="linenos">337</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-338"><a href="#L-338"><span class="linenos">338</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-339"><a href="#L-339"><span class="linenos">339</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-340"><a href="#L-340"><span class="linenos">340</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-341"><a href="#L-341"><span class="linenos">341</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-342"><a href="#L-342"><span class="linenos">342</span></a><span class="sd">    ...      &quot;Test AndState&quot;: {&quot;plugin&quot;: &quot;AndState&quot;,</span>
+</span><span id="L-343"><a href="#L-343"><span class="linenos">343</span></a><span class="sd">    ...                        &quot;states&quot;: [&quot;Test State 1&quot;, &quot;Test State 2&quot;]}},</span>
+</span><span id="L-344"><a href="#L-344"><span class="linenos">344</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-345"><a href="#L-345"><span class="linenos">345</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-346"><a href="#L-346"><span class="linenos">346</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-347"><a href="#L-347"><span class="linenos">347</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-348"><a href="#L-348"><span class="linenos">348</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-349"><a href="#L-349"><span class="linenos">349</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="L-350"><a href="#L-350"><span class="linenos">350</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndState&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-351"><a href="#L-351"><span class="linenos">351</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndState&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="L-352"><a href="#L-352"><span class="linenos">352</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-353"><a href="#L-353"><span class="linenos">353</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-354"><a href="#L-354"><span class="linenos">354</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-355"><a href="#L-355"><span class="linenos">355</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-356"><a href="#L-356"><span class="linenos">356</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="L-357"><a href="#L-357"><span class="linenos">357</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-358"><a href="#L-358"><span class="linenos">358</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-359"><a href="#L-359"><span class="linenos">359</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-360"><a href="#L-360"><span class="linenos">360</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-361"><a href="#L-361"><span class="linenos">361</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-362"><a href="#L-362"><span class="linenos">362</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>
+</span><span id="L-363"><a href="#L-363"><span class="linenos">363</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-364"><a href="#L-364"><span class="linenos">364</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-365"><a href="#L-365"><span class="linenos">365</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-366"><a href="#L-366"><span class="linenos">366</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>
+</span><span id="L-367"><a href="#L-367"><span class="linenos">367</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="L-368"><a href="#L-368"><span class="linenos">368</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-369"><a href="#L-369"><span class="linenos">369</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-370"><a href="#L-370"><span class="linenos">370</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;,</span>
+</span><span id="L-371"><a href="#L-371"><span class="linenos">371</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="L-372"><a href="#L-372"><span class="linenos">372</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-373"><a href="#L-373"><span class="linenos">373</span></a>
+</span><span id="L-374"><a href="#L-374"><span class="linenos">374</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-375"><a href="#L-375"><span class="linenos">375</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}},</span>
+</span><span id="L-376"><a href="#L-376"><span class="linenos">376</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">],</span>
+</span><span id="L-377"><a href="#L-377"><span class="linenos">377</span></a>    <span class="p">}</span>
+</span><span id="L-378"><a href="#L-378"><span class="linenos">378</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for AndState plugin configuration.</span>
+</span><span id="L-379"><a href="#L-379"><span class="linenos">379</span></a>
+</span><span id="L-380"><a href="#L-380"><span class="linenos">380</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-381"><a href="#L-381"><span class="linenos">381</span></a>
+</span><span id="L-382"><a href="#L-382"><span class="linenos">382</span></a><span class="sd">    - &#39;states&#39;: list of names of combined states.</span>
+</span><span id="L-383"><a href="#L-383"><span class="linenos">383</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-384"><a href="#L-384"><span class="linenos">384</span></a>
+</span><span id="L-385"><a href="#L-385"><span class="linenos">385</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-386"><a href="#L-386"><span class="linenos">386</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-387"><a href="#L-387"><span class="linenos">387</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-388"><a href="#L-388"><span class="linenos">388</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-389"><a href="#L-389"><span class="linenos">389</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">]:</span>
+</span><span id="L-390"><a href="#L-390"><span class="linenos">390</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="L-391"><a href="#L-391"><span class="linenos">391</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-392"><a href="#L-392"><span class="linenos">392</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-393"><a href="#L-393"><span class="linenos">393</span></a>                <span class="p">)</span>
+</span><span id="L-394"><a href="#L-394"><span class="linenos">394</span></a>            <span class="p">)</span>
+</span><span id="L-395"><a href="#L-395"><span class="linenos">395</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-396"><a href="#L-396"><span class="linenos">396</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-397"><a href="#L-397"><span class="linenos">397</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-398"><a href="#L-398"><span class="linenos">398</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-399"><a href="#L-399"><span class="linenos">399</span></a>            <span class="s2">&quot;AndState&quot;</span><span class="p">,</span>
+</span><span id="L-400"><a href="#L-400"><span class="linenos">400</span></a>            <span class="p">[</span>
+</span><span id="L-401"><a href="#L-401"><span class="linenos">401</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-402"><a href="#L-402"><span class="linenos">402</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-403"><a href="#L-403"><span class="linenos">403</span></a>                <span class="p">),</span>
+</span><span id="L-404"><a href="#L-404"><span class="linenos">404</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="L-405"><a href="#L-405"><span class="linenos">405</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-406"><a href="#L-406"><span class="linenos">406</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="L-407"><a href="#L-407"><span class="linenos">407</span></a>                <span class="p">),</span>
+</span><span id="L-408"><a href="#L-408"><span class="linenos">408</span></a>            <span class="p">],</span>
+</span><span id="L-409"><a href="#L-409"><span class="linenos">409</span></a>            <span class="p">[</span>
+</span><span id="L-410"><a href="#L-410"><span class="linenos">410</span></a>                <span class="p">(</span>
+</span><span id="L-411"><a href="#L-411"><span class="linenos">411</span></a>                    <span class="p">[</span>
+</span><span id="L-412"><a href="#L-412"><span class="linenos">412</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-413"><a href="#L-413"><span class="linenos">413</span></a>                            <span class="p">{</span>
+</span><span id="L-414"><a href="#L-414"><span class="linenos">414</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-415"><a href="#L-415"><span class="linenos">415</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-416"><a href="#L-416"><span class="linenos">416</span></a>                            <span class="p">}</span>
+</span><span id="L-417"><a href="#L-417"><span class="linenos">417</span></a>                        <span class="p">)</span>
+</span><span id="L-418"><a href="#L-418"><span class="linenos">418</span></a>                    <span class="p">],</span>
+</span><span id="L-419"><a href="#L-419"><span class="linenos">419</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="L-420"><a href="#L-420"><span class="linenos">420</span></a>                <span class="p">),</span>
+</span><span id="L-421"><a href="#L-421"><span class="linenos">421</span></a>                <span class="p">(</span>
+</span><span id="L-422"><a href="#L-422"><span class="linenos">422</span></a>                    <span class="p">[</span>
+</span><span id="L-423"><a href="#L-423"><span class="linenos">423</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-424"><a href="#L-424"><span class="linenos">424</span></a>                            <span class="p">{</span>
+</span><span id="L-425"><a href="#L-425"><span class="linenos">425</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-426"><a href="#L-426"><span class="linenos">426</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="L-427"><a href="#L-427"><span class="linenos">427</span></a>                            <span class="p">}</span>
+</span><span id="L-428"><a href="#L-428"><span class="linenos">428</span></a>                        <span class="p">)</span>
+</span><span id="L-429"><a href="#L-429"><span class="linenos">429</span></a>                    <span class="p">],</span>
+</span><span id="L-430"><a href="#L-430"><span class="linenos">430</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="L-431"><a href="#L-431"><span class="linenos">431</span></a>                <span class="p">),</span>
+</span><span id="L-432"><a href="#L-432"><span class="linenos">432</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="L-433"><a href="#L-433"><span class="linenos">433</span></a>            <span class="p">],</span>
+</span><span id="L-434"><a href="#L-434"><span class="linenos">434</span></a>        <span class="p">)</span>
+</span><span id="L-435"><a href="#L-435"><span class="linenos">435</span></a>
+</span><span id="L-436"><a href="#L-436"><span class="linenos">436</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-437"><a href="#L-437"><span class="linenos">437</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="L-438"><a href="#L-438"><span class="linenos">438</span></a>
+</span><span id="L-439"><a href="#L-439"><span class="linenos">439</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-440"><a href="#L-440"><span class="linenos">440</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="L-441"><a href="#L-441"><span class="linenos">441</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="L-442"><a href="#L-442"><span class="linenos">442</span></a>
+</span><span id="L-443"><a href="#L-443"><span class="linenos">443</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-444"><a href="#L-444"><span class="linenos">444</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-445"><a href="#L-445"><span class="linenos">445</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-446"><a href="#L-446"><span class="linenos">446</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="L-447"><a href="#L-447"><span class="linenos">447</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-448"><a href="#L-448"><span class="linenos">448</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="L-449"><a href="#L-449"><span class="linenos">449</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="L-450"><a href="#L-450"><span class="linenos">450</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-451"><a href="#L-451"><span class="linenos">451</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">,</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">})</span>
+</span><span id="L-452"><a href="#L-452"><span class="linenos">452</span></a>            <span class="p">)</span>
+</span><span id="L-453"><a href="#L-453"><span class="linenos">453</span></a>
+</span><span id="L-454"><a href="#L-454"><span class="linenos">454</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-455"><a href="#L-455"><span class="linenos">455</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-456"><a href="#L-456"><span class="linenos">456</span></a>        <span class="k">pass</span>
+</span><span id="L-457"><a href="#L-457"><span class="linenos">457</span></a>
+</span><span id="L-458"><a href="#L-458"><span class="linenos">458</span></a>
+</span><span id="L-459"><a href="#L-459"><span class="linenos">459</span></a><span class="k">class</span><span class="w"> </span><span class="nc">OrState</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-460"><a href="#L-460"><span class="linenos">460</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define disjunction of states.</span>
+</span><span id="L-461"><a href="#L-461"><span class="linenos">461</span></a>
+</span><span id="L-462"><a href="#L-462"><span class="linenos">462</span></a><span class="sd">    The &quot;states&quot; configuration key gets an array of states to be combined.</span>
+</span><span id="L-463"><a href="#L-463"><span class="linenos">463</span></a><span class="sd">    An OrState plugin client reacts to &quot;get state&quot; commands and sends</span>
+</span><span id="L-464"><a href="#L-464"><span class="linenos">464</span></a><span class="sd">    &quot;changed&quot; events when a change in one of the combined states leads to</span>
+</span><span id="L-465"><a href="#L-465"><span class="linenos">465</span></a><span class="sd">    a change for the disjunction:</span>
+</span><span id="L-466"><a href="#L-466"><span class="linenos">466</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-467"><a href="#L-467"><span class="linenos">467</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-468"><a href="#L-468"><span class="linenos">468</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-469"><a href="#L-469"><span class="linenos">469</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-470"><a href="#L-470"><span class="linenos">470</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-471"><a href="#L-471"><span class="linenos">471</span></a><span class="sd">    ...      &quot;Test OrState&quot;: {&quot;plugin&quot;: &quot;OrState&quot;,</span>
+</span><span id="L-472"><a href="#L-472"><span class="linenos">472</span></a><span class="sd">    ...                       &quot;states&quot;: [&quot;Test State 1&quot;, &quot;Test State 2&quot;]}},</span>
+</span><span id="L-473"><a href="#L-473"><span class="linenos">473</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-474"><a href="#L-474"><span class="linenos">474</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-475"><a href="#L-475"><span class="linenos">475</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-476"><a href="#L-476"><span class="linenos">476</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-477"><a href="#L-477"><span class="linenos">477</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-478"><a href="#L-478"><span class="linenos">478</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="L-479"><a href="#L-479"><span class="linenos">479</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrState&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-480"><a href="#L-480"><span class="linenos">480</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrState&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="L-481"><a href="#L-481"><span class="linenos">481</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-482"><a href="#L-482"><span class="linenos">482</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-483"><a href="#L-483"><span class="linenos">483</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-484"><a href="#L-484"><span class="linenos">484</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-485"><a href="#L-485"><span class="linenos">485</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="L-486"><a href="#L-486"><span class="linenos">486</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-487"><a href="#L-487"><span class="linenos">487</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-488"><a href="#L-488"><span class="linenos">488</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-489"><a href="#L-489"><span class="linenos">489</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-490"><a href="#L-490"><span class="linenos">490</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-491"><a href="#L-491"><span class="linenos">491</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-492"><a href="#L-492"><span class="linenos">492</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>
+</span><span id="L-493"><a href="#L-493"><span class="linenos">493</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-494"><a href="#L-494"><span class="linenos">494</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-495"><a href="#L-495"><span class="linenos">495</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>
+</span><span id="L-496"><a href="#L-496"><span class="linenos">496</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="L-497"><a href="#L-497"><span class="linenos">497</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-498"><a href="#L-498"><span class="linenos">498</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrState&#39;,</span>
+</span><span id="L-499"><a href="#L-499"><span class="linenos">499</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="L-500"><a href="#L-500"><span class="linenos">500</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-501"><a href="#L-501"><span class="linenos">501</span></a>
+</span><span id="L-502"><a href="#L-502"><span class="linenos">502</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-503"><a href="#L-503"><span class="linenos">503</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}},</span>
+</span><span id="L-504"><a href="#L-504"><span class="linenos">504</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">],</span>
+</span><span id="L-505"><a href="#L-505"><span class="linenos">505</span></a>    <span class="p">}</span>
+</span><span id="L-506"><a href="#L-506"><span class="linenos">506</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for OrState plugin configuration.</span>
+</span><span id="L-507"><a href="#L-507"><span class="linenos">507</span></a>
+</span><span id="L-508"><a href="#L-508"><span class="linenos">508</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-509"><a href="#L-509"><span class="linenos">509</span></a>
+</span><span id="L-510"><a href="#L-510"><span class="linenos">510</span></a><span class="sd">    - &#39;states&#39;: list of names of combined states.</span>
+</span><span id="L-511"><a href="#L-511"><span class="linenos">511</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-512"><a href="#L-512"><span class="linenos">512</span></a>
+</span><span id="L-513"><a href="#L-513"><span class="linenos">513</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-514"><a href="#L-514"><span class="linenos">514</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-515"><a href="#L-515"><span class="linenos">515</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-516"><a href="#L-516"><span class="linenos">516</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-517"><a href="#L-517"><span class="linenos">517</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">]:</span>
+</span><span id="L-518"><a href="#L-518"><span class="linenos">518</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="L-519"><a href="#L-519"><span class="linenos">519</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-520"><a href="#L-520"><span class="linenos">520</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-521"><a href="#L-521"><span class="linenos">521</span></a>                <span class="p">)</span>
+</span><span id="L-522"><a href="#L-522"><span class="linenos">522</span></a>            <span class="p">)</span>
+</span><span id="L-523"><a href="#L-523"><span class="linenos">523</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-524"><a href="#L-524"><span class="linenos">524</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-525"><a href="#L-525"><span class="linenos">525</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-526"><a href="#L-526"><span class="linenos">526</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-527"><a href="#L-527"><span class="linenos">527</span></a>            <span class="s2">&quot;OrState&quot;</span><span class="p">,</span>
+</span><span id="L-528"><a href="#L-528"><span class="linenos">528</span></a>            <span class="p">[</span>
+</span><span id="L-529"><a href="#L-529"><span class="linenos">529</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-530"><a href="#L-530"><span class="linenos">530</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-531"><a href="#L-531"><span class="linenos">531</span></a>                <span class="p">),</span>
+</span><span id="L-532"><a href="#L-532"><span class="linenos">532</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="L-533"><a href="#L-533"><span class="linenos">533</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-534"><a href="#L-534"><span class="linenos">534</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="L-535"><a href="#L-535"><span class="linenos">535</span></a>                <span class="p">),</span>
+</span><span id="L-536"><a href="#L-536"><span class="linenos">536</span></a>            <span class="p">],</span>
+</span><span id="L-537"><a href="#L-537"><span class="linenos">537</span></a>            <span class="p">[</span>
+</span><span id="L-538"><a href="#L-538"><span class="linenos">538</span></a>                <span class="p">(</span>
+</span><span id="L-539"><a href="#L-539"><span class="linenos">539</span></a>                    <span class="p">[</span>
+</span><span id="L-540"><a href="#L-540"><span class="linenos">540</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-541"><a href="#L-541"><span class="linenos">541</span></a>                            <span class="p">{</span>
+</span><span id="L-542"><a href="#L-542"><span class="linenos">542</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-543"><a href="#L-543"><span class="linenos">543</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-544"><a href="#L-544"><span class="linenos">544</span></a>                            <span class="p">}</span>
+</span><span id="L-545"><a href="#L-545"><span class="linenos">545</span></a>                        <span class="p">)</span>
+</span><span id="L-546"><a href="#L-546"><span class="linenos">546</span></a>                    <span class="p">],</span>
+</span><span id="L-547"><a href="#L-547"><span class="linenos">547</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="L-548"><a href="#L-548"><span class="linenos">548</span></a>                <span class="p">),</span>
+</span><span id="L-549"><a href="#L-549"><span class="linenos">549</span></a>                <span class="p">(</span>
+</span><span id="L-550"><a href="#L-550"><span class="linenos">550</span></a>                    <span class="p">[</span>
+</span><span id="L-551"><a href="#L-551"><span class="linenos">551</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-552"><a href="#L-552"><span class="linenos">552</span></a>                            <span class="p">{</span>
+</span><span id="L-553"><a href="#L-553"><span class="linenos">553</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-554"><a href="#L-554"><span class="linenos">554</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="L-555"><a href="#L-555"><span class="linenos">555</span></a>                            <span class="p">}</span>
+</span><span id="L-556"><a href="#L-556"><span class="linenos">556</span></a>                        <span class="p">)</span>
+</span><span id="L-557"><a href="#L-557"><span class="linenos">557</span></a>                    <span class="p">],</span>
+</span><span id="L-558"><a href="#L-558"><span class="linenos">558</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="L-559"><a href="#L-559"><span class="linenos">559</span></a>                <span class="p">),</span>
+</span><span id="L-560"><a href="#L-560"><span class="linenos">560</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="L-561"><a href="#L-561"><span class="linenos">561</span></a>            <span class="p">],</span>
+</span><span id="L-562"><a href="#L-562"><span class="linenos">562</span></a>        <span class="p">)</span>
+</span><span id="L-563"><a href="#L-563"><span class="linenos">563</span></a>
+</span><span id="L-564"><a href="#L-564"><span class="linenos">564</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-565"><a href="#L-565"><span class="linenos">565</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="L-566"><a href="#L-566"><span class="linenos">566</span></a>
+</span><span id="L-567"><a href="#L-567"><span class="linenos">567</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-568"><a href="#L-568"><span class="linenos">568</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="L-569"><a href="#L-569"><span class="linenos">569</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="L-570"><a href="#L-570"><span class="linenos">570</span></a>
+</span><span id="L-571"><a href="#L-571"><span class="linenos">571</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-572"><a href="#L-572"><span class="linenos">572</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-573"><a href="#L-573"><span class="linenos">573</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-574"><a href="#L-574"><span class="linenos">574</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="L-575"><a href="#L-575"><span class="linenos">575</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-576"><a href="#L-576"><span class="linenos">576</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="L-577"><a href="#L-577"><span class="linenos">577</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="L-578"><a href="#L-578"><span class="linenos">578</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-579"><a href="#L-579"><span class="linenos">579</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">,</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">})</span>
+</span><span id="L-580"><a href="#L-580"><span class="linenos">580</span></a>            <span class="p">)</span>
+</span><span id="L-581"><a href="#L-581"><span class="linenos">581</span></a>
+</span><span id="L-582"><a href="#L-582"><span class="linenos">582</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-583"><a href="#L-583"><span class="linenos">583</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-584"><a href="#L-584"><span class="linenos">584</span></a>        <span class="k">pass</span>
+</span><span id="L-585"><a href="#L-585"><span class="linenos">585</span></a>
+</span><span id="L-586"><a href="#L-586"><span class="linenos">586</span></a>
+</span><span id="L-587"><a href="#L-587"><span class="linenos">587</span></a><span class="k">class</span><span class="w"> </span><span class="nc">AndSet</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-588"><a href="#L-588"><span class="linenos">588</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Set state based on conjunction of other states.</span>
+</span><span id="L-589"><a href="#L-589"><span class="linenos">589</span></a>
+</span><span id="L-590"><a href="#L-590"><span class="linenos">590</span></a><span class="sd">    The &quot;input states&quot; configuration key gets an array of states used to</span>
+</span><span id="L-591"><a href="#L-591"><span class="linenos">591</span></a><span class="sd">    determine the state in the &quot;output state&quot; configuration key:</span>
+</span><span id="L-592"><a href="#L-592"><span class="linenos">592</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-593"><a href="#L-593"><span class="linenos">593</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-594"><a href="#L-594"><span class="linenos">594</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-595"><a href="#L-595"><span class="linenos">595</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-596"><a href="#L-596"><span class="linenos">596</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-597"><a href="#L-597"><span class="linenos">597</span></a><span class="sd">    ...      &quot;Test State 3&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-598"><a href="#L-598"><span class="linenos">598</span></a><span class="sd">    ...      &quot;Test AndSet&quot;: {&quot;plugin&quot;: &quot;AndSet&quot;,</span>
+</span><span id="L-599"><a href="#L-599"><span class="linenos">599</span></a><span class="sd">    ...                      &quot;input states&quot;: [&quot;Test State 1&quot;,</span>
+</span><span id="L-600"><a href="#L-600"><span class="linenos">600</span></a><span class="sd">    ...                                       &quot;Test State 2&quot;],</span>
+</span><span id="L-601"><a href="#L-601"><span class="linenos">601</span></a><span class="sd">    ...                      &quot;output state&quot;: &quot;Test State 3&quot;}},</span>
+</span><span id="L-602"><a href="#L-602"><span class="linenos">602</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-603"><a href="#L-603"><span class="linenos">603</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-604"><a href="#L-604"><span class="linenos">604</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-605"><a href="#L-605"><span class="linenos">605</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-606"><a href="#L-606"><span class="linenos">606</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndSet&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-607"><a href="#L-607"><span class="linenos">607</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-608"><a href="#L-608"><span class="linenos">608</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="L-609"><a href="#L-609"><span class="linenos">609</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndSet&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-610"><a href="#L-610"><span class="linenos">610</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndSet&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="L-611"><a href="#L-611"><span class="linenos">611</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-612"><a href="#L-612"><span class="linenos">612</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-613"><a href="#L-613"><span class="linenos">613</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-614"><a href="#L-614"><span class="linenos">614</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-615"><a href="#L-615"><span class="linenos">615</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="L-616"><a href="#L-616"><span class="linenos">616</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-617"><a href="#L-617"><span class="linenos">617</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-618"><a href="#L-618"><span class="linenos">618</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="L-619"><a href="#L-619"><span class="linenos">619</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-620"><a href="#L-620"><span class="linenos">620</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-621"><a href="#L-621"><span class="linenos">621</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-622"><a href="#L-622"><span class="linenos">622</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-623"><a href="#L-623"><span class="linenos">623</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="L-624"><a href="#L-624"><span class="linenos">624</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-625"><a href="#L-625"><span class="linenos">625</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="L-626"><a href="#L-626"><span class="linenos">626</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-627"><a href="#L-627"><span class="linenos">627</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="L-628"><a href="#L-628"><span class="linenos">628</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-629"><a href="#L-629"><span class="linenos">629</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-630"><a href="#L-630"><span class="linenos">630</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-631"><a href="#L-631"><span class="linenos">631</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-632"><a href="#L-632"><span class="linenos">632</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="L-633"><a href="#L-633"><span class="linenos">633</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="L-634"><a href="#L-634"><span class="linenos">634</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="L-635"><a href="#L-635"><span class="linenos">635</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-636"><a href="#L-636"><span class="linenos">636</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="L-637"><a href="#L-637"><span class="linenos">637</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-638"><a href="#L-638"><span class="linenos">638</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="L-639"><a href="#L-639"><span class="linenos">639</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="L-640"><a href="#L-640"><span class="linenos">640</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-641"><a href="#L-641"><span class="linenos">641</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-642"><a href="#L-642"><span class="linenos">642</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-643"><a href="#L-643"><span class="linenos">643</span></a>
+</span><span id="L-644"><a href="#L-644"><span class="linenos">644</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-645"><a href="#L-645"><span class="linenos">645</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-646"><a href="#L-646"><span class="linenos">646</span></a>            <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}},</span>
+</span><span id="L-647"><a href="#L-647"><span class="linenos">647</span></a>            <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="L-648"><a href="#L-648"><span class="linenos">648</span></a>        <span class="p">},</span>
+</span><span id="L-649"><a href="#L-649"><span class="linenos">649</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">,</span> <span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="L-650"><a href="#L-650"><span class="linenos">650</span></a>    <span class="p">}</span>
+</span><span id="L-651"><a href="#L-651"><span class="linenos">651</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for AndSet plugin configuration.</span>
+</span><span id="L-652"><a href="#L-652"><span class="linenos">652</span></a>
+</span><span id="L-653"><a href="#L-653"><span class="linenos">653</span></a><span class="sd">    Required configuration keys:</span>
+</span><span id="L-654"><a href="#L-654"><span class="linenos">654</span></a>
+</span><span id="L-655"><a href="#L-655"><span class="linenos">655</span></a><span class="sd">    - &#39;input states&#39;: list of names of combined states.</span>
+</span><span id="L-656"><a href="#L-656"><span class="linenos">656</span></a><span class="sd">    - &#39;output state&#39;: name of state to be set.</span>
+</span><span id="L-657"><a href="#L-657"><span class="linenos">657</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-658"><a href="#L-658"><span class="linenos">658</span></a>
+</span><span id="L-659"><a href="#L-659"><span class="linenos">659</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-660"><a href="#L-660"><span class="linenos">660</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-661"><a href="#L-661"><span class="linenos">661</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-662"><a href="#L-662"><span class="linenos">662</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-663"><a href="#L-663"><span class="linenos">663</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">]:</span>
+</span><span id="L-664"><a href="#L-664"><span class="linenos">664</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="L-665"><a href="#L-665"><span class="linenos">665</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-666"><a href="#L-666"><span class="linenos">666</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-667"><a href="#L-667"><span class="linenos">667</span></a>                <span class="p">)</span>
+</span><span id="L-668"><a href="#L-668"><span class="linenos">668</span></a>            <span class="p">)</span>
+</span><span id="L-669"><a href="#L-669"><span class="linenos">669</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-670"><a href="#L-670"><span class="linenos">670</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-671"><a href="#L-671"><span class="linenos">671</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-672"><a href="#L-672"><span class="linenos">672</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-673"><a href="#L-673"><span class="linenos">673</span></a>            <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+</span><span id="L-674"><a href="#L-674"><span class="linenos">674</span></a>            <span class="p">[</span>
+</span><span id="L-675"><a href="#L-675"><span class="linenos">675</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-676"><a href="#L-676"><span class="linenos">676</span></a>                    <span class="p">{</span>
+</span><span id="L-677"><a href="#L-677"><span class="linenos">677</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">]},</span>
+</span><span id="L-678"><a href="#L-678"><span class="linenos">678</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="L-679"><a href="#L-679"><span class="linenos">679</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="L-680"><a href="#L-680"><span class="linenos">680</span></a>                    <span class="p">}</span>
+</span><span id="L-681"><a href="#L-681"><span class="linenos">681</span></a>                <span class="p">),</span>
+</span><span id="L-682"><a href="#L-682"><span class="linenos">682</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-683"><a href="#L-683"><span class="linenos">683</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="L-684"><a href="#L-684"><span class="linenos">684</span></a>                <span class="p">),</span>
+</span><span id="L-685"><a href="#L-685"><span class="linenos">685</span></a>            <span class="p">],</span>
+</span><span id="L-686"><a href="#L-686"><span class="linenos">686</span></a>            <span class="p">[</span>
+</span><span id="L-687"><a href="#L-687"><span class="linenos">687</span></a>                <span class="p">(</span>
+</span><span id="L-688"><a href="#L-688"><span class="linenos">688</span></a>                    <span class="p">[</span>
+</span><span id="L-689"><a href="#L-689"><span class="linenos">689</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-690"><a href="#L-690"><span class="linenos">690</span></a>                            <span class="p">{</span>
+</span><span id="L-691"><a href="#L-691"><span class="linenos">691</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-692"><a href="#L-692"><span class="linenos">692</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-693"><a href="#L-693"><span class="linenos">693</span></a>                            <span class="p">}</span>
+</span><span id="L-694"><a href="#L-694"><span class="linenos">694</span></a>                        <span class="p">)</span>
+</span><span id="L-695"><a href="#L-695"><span class="linenos">695</span></a>                    <span class="p">],</span>
+</span><span id="L-696"><a href="#L-696"><span class="linenos">696</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="L-697"><a href="#L-697"><span class="linenos">697</span></a>                <span class="p">),</span>
+</span><span id="L-698"><a href="#L-698"><span class="linenos">698</span></a>                <span class="p">(</span>
+</span><span id="L-699"><a href="#L-699"><span class="linenos">699</span></a>                    <span class="p">[</span>
+</span><span id="L-700"><a href="#L-700"><span class="linenos">700</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-701"><a href="#L-701"><span class="linenos">701</span></a>                            <span class="p">{</span>
+</span><span id="L-702"><a href="#L-702"><span class="linenos">702</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-703"><a href="#L-703"><span class="linenos">703</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="L-704"><a href="#L-704"><span class="linenos">704</span></a>                            <span class="p">}</span>
+</span><span id="L-705"><a href="#L-705"><span class="linenos">705</span></a>                        <span class="p">)</span>
+</span><span id="L-706"><a href="#L-706"><span class="linenos">706</span></a>                    <span class="p">],</span>
+</span><span id="L-707"><a href="#L-707"><span class="linenos">707</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="L-708"><a href="#L-708"><span class="linenos">708</span></a>                <span class="p">),</span>
+</span><span id="L-709"><a href="#L-709"><span class="linenos">709</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="L-710"><a href="#L-710"><span class="linenos">710</span></a>            <span class="p">],</span>
+</span><span id="L-711"><a href="#L-711"><span class="linenos">711</span></a>        <span class="p">)</span>
+</span><span id="L-712"><a href="#L-712"><span class="linenos">712</span></a>
+</span><span id="L-713"><a href="#L-713"><span class="linenos">713</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-714"><a href="#L-714"><span class="linenos">714</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-715"><a href="#L-715"><span class="linenos">715</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-716"><a href="#L-716"><span class="linenos">716</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-717"><a href="#L-717"><span class="linenos">717</span></a>                <span class="p">{</span>
+</span><span id="L-718"><a href="#L-718"><span class="linenos">718</span></a>                    <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="L-719"><a href="#L-719"><span class="linenos">719</span></a>                    <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="L-720"><a href="#L-720"><span class="linenos">720</span></a>                    <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="L-721"><a href="#L-721"><span class="linenos">721</span></a>                <span class="p">},</span>
+</span><span id="L-722"><a href="#L-722"><span class="linenos">722</span></a>            <span class="p">)</span>
+</span><span id="L-723"><a href="#L-723"><span class="linenos">723</span></a>        <span class="p">)</span>
+</span><span id="L-724"><a href="#L-724"><span class="linenos">724</span></a>
+</span><span id="L-725"><a href="#L-725"><span class="linenos">725</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-726"><a href="#L-726"><span class="linenos">726</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="L-727"><a href="#L-727"><span class="linenos">727</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="L-728"><a href="#L-728"><span class="linenos">728</span></a>
+</span><span id="L-729"><a href="#L-729"><span class="linenos">729</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-730"><a href="#L-730"><span class="linenos">730</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-731"><a href="#L-731"><span class="linenos">731</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-732"><a href="#L-732"><span class="linenos">732</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="L-733"><a href="#L-733"><span class="linenos">733</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-734"><a href="#L-734"><span class="linenos">734</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="L-735"><a href="#L-735"><span class="linenos">735</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="L-736"><a href="#L-736"><span class="linenos">736</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-737"><a href="#L-737"><span class="linenos">737</span></a>                <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-738"><a href="#L-738"><span class="linenos">738</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-739"><a href="#L-739"><span class="linenos">739</span></a>                    <span class="p">{</span>
+</span><span id="L-740"><a href="#L-740"><span class="linenos">740</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="L-741"><a href="#L-741"><span class="linenos">741</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="L-742"><a href="#L-742"><span class="linenos">742</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="L-743"><a href="#L-743"><span class="linenos">743</span></a>                    <span class="p">},</span>
+</span><span id="L-744"><a href="#L-744"><span class="linenos">744</span></a>                <span class="p">)</span>
+</span><span id="L-745"><a href="#L-745"><span class="linenos">745</span></a>            <span class="p">)</span>
+</span><span id="L-746"><a href="#L-746"><span class="linenos">746</span></a>
+</span><span id="L-747"><a href="#L-747"><span class="linenos">747</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-748"><a href="#L-748"><span class="linenos">748</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-749"><a href="#L-749"><span class="linenos">749</span></a>        <span class="k">pass</span>
+</span><span id="L-750"><a href="#L-750"><span class="linenos">750</span></a>
+</span><span id="L-751"><a href="#L-751"><span class="linenos">751</span></a>
+</span><span id="L-752"><a href="#L-752"><span class="linenos">752</span></a><span class="k">class</span><span class="w"> </span><span class="nc">OrSet</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-753"><a href="#L-753"><span class="linenos">753</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Set state based on disjunction of other states.</span>
+</span><span id="L-754"><a href="#L-754"><span class="linenos">754</span></a>
+</span><span id="L-755"><a href="#L-755"><span class="linenos">755</span></a><span class="sd">    The &quot;input states&quot; configuration key gets an array of states used to</span>
+</span><span id="L-756"><a href="#L-756"><span class="linenos">756</span></a><span class="sd">    determine the state in the &quot;output state&quot; configuration key:</span>
+</span><span id="L-757"><a href="#L-757"><span class="linenos">757</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="L-758"><a href="#L-758"><span class="linenos">758</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-759"><a href="#L-759"><span class="linenos">759</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-760"><a href="#L-760"><span class="linenos">760</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-761"><a href="#L-761"><span class="linenos">761</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-762"><a href="#L-762"><span class="linenos">762</span></a><span class="sd">    ...      &quot;Test State 3&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="L-763"><a href="#L-763"><span class="linenos">763</span></a><span class="sd">    ...      &quot;Test OrSet&quot;: {&quot;plugin&quot;: &quot;OrSet&quot;,</span>
+</span><span id="L-764"><a href="#L-764"><span class="linenos">764</span></a><span class="sd">    ...                      &quot;input states&quot;: [&quot;Test State 1&quot;,</span>
+</span><span id="L-765"><a href="#L-765"><span class="linenos">765</span></a><span class="sd">    ...                                       &quot;Test State 2&quot;],</span>
+</span><span id="L-766"><a href="#L-766"><span class="linenos">766</span></a><span class="sd">    ...                      &quot;output state&quot;: &quot;Test State 3&quot;}},</span>
+</span><span id="L-767"><a href="#L-767"><span class="linenos">767</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-768"><a href="#L-768"><span class="linenos">768</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-769"><a href="#L-769"><span class="linenos">769</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrSet&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="L-770"><a href="#L-770"><span class="linenos">770</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-771"><a href="#L-771"><span class="linenos">771</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="L-772"><a href="#L-772"><span class="linenos">772</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="L-773"><a href="#L-773"><span class="linenos">773</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="L-774"><a href="#L-774"><span class="linenos">774</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrSet&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="L-775"><a href="#L-775"><span class="linenos">775</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-776"><a href="#L-776"><span class="linenos">776</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="L-777"><a href="#L-777"><span class="linenos">777</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-778"><a href="#L-778"><span class="linenos">778</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-779"><a href="#L-779"><span class="linenos">779</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>
+</span><span id="L-780"><a href="#L-780"><span class="linenos">780</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="L-781"><a href="#L-781"><span class="linenos">781</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-782"><a href="#L-782"><span class="linenos">782</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="L-783"><a href="#L-783"><span class="linenos">783</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-784"><a href="#L-784"><span class="linenos">784</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="L-785"><a href="#L-785"><span class="linenos">785</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-786"><a href="#L-786"><span class="linenos">786</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="L-787"><a href="#L-787"><span class="linenos">787</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="L-788"><a href="#L-788"><span class="linenos">788</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="L-789"><a href="#L-789"><span class="linenos">789</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="L-790"><a href="#L-790"><span class="linenos">790</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-791"><a href="#L-791"><span class="linenos">791</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-792"><a href="#L-792"><span class="linenos">792</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="L-793"><a href="#L-793"><span class="linenos">793</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>
+</span><span id="L-794"><a href="#L-794"><span class="linenos">794</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="L-795"><a href="#L-795"><span class="linenos">795</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="L-796"><a href="#L-796"><span class="linenos">796</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrSet&#39;,</span>
+</span><span id="L-797"><a href="#L-797"><span class="linenos">797</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="L-798"><a href="#L-798"><span class="linenos">798</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-799"><a href="#L-799"><span class="linenos">799</span></a>
+</span><span id="L-800"><a href="#L-800"><span class="linenos">800</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-801"><a href="#L-801"><span class="linenos">801</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-802"><a href="#L-802"><span class="linenos">802</span></a>            <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}},</span>
+</span><span id="L-803"><a href="#L-803"><span class="linenos">803</span></a>            <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="L-804"><a href="#L-804"><span class="linenos">804</span></a>        <span class="p">},</span>
+</span><span id="L-805"><a href="#L-805"><span class="linenos">805</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">,</span> <span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="L-806"><a href="#L-806"><span class="linenos">806</span></a>    <span class="p">}</span>
+</span><span id="L-807"><a href="#L-807"><span class="linenos">807</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for OrSet plugin configuration.</span>
+</span><span id="L-808"><a href="#L-808"><span class="linenos">808</span></a>
+</span><span id="L-809"><a href="#L-809"><span class="linenos">809</span></a><span class="sd">    Required configuration keys:</span>
+</span><span id="L-810"><a href="#L-810"><span class="linenos">810</span></a>
+</span><span id="L-811"><a href="#L-811"><span class="linenos">811</span></a><span class="sd">    - &#39;input states&#39;: list of names of combined states.</span>
+</span><span id="L-812"><a href="#L-812"><span class="linenos">812</span></a><span class="sd">    - &#39;output state&#39;: name of state to be set.</span>
+</span><span id="L-813"><a href="#L-813"><span class="linenos">813</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-814"><a href="#L-814"><span class="linenos">814</span></a>
+</span><span id="L-815"><a href="#L-815"><span class="linenos">815</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-816"><a href="#L-816"><span class="linenos">816</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-817"><a href="#L-817"><span class="linenos">817</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-818"><a href="#L-818"><span class="linenos">818</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-819"><a href="#L-819"><span class="linenos">819</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">]:</span>
+</span><span id="L-820"><a href="#L-820"><span class="linenos">820</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="L-821"><a href="#L-821"><span class="linenos">821</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-822"><a href="#L-822"><span class="linenos">822</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="L-823"><a href="#L-823"><span class="linenos">823</span></a>                <span class="p">)</span>
+</span><span id="L-824"><a href="#L-824"><span class="linenos">824</span></a>            <span class="p">)</span>
+</span><span id="L-825"><a href="#L-825"><span class="linenos">825</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="L-826"><a href="#L-826"><span class="linenos">826</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-827"><a href="#L-827"><span class="linenos">827</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-828"><a href="#L-828"><span class="linenos">828</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-829"><a href="#L-829"><span class="linenos">829</span></a>            <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+</span><span id="L-830"><a href="#L-830"><span class="linenos">830</span></a>            <span class="p">[</span>
+</span><span id="L-831"><a href="#L-831"><span class="linenos">831</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-832"><a href="#L-832"><span class="linenos">832</span></a>                    <span class="p">{</span>
+</span><span id="L-833"><a href="#L-833"><span class="linenos">833</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">]},</span>
+</span><span id="L-834"><a href="#L-834"><span class="linenos">834</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="L-835"><a href="#L-835"><span class="linenos">835</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="L-836"><a href="#L-836"><span class="linenos">836</span></a>                    <span class="p">}</span>
+</span><span id="L-837"><a href="#L-837"><span class="linenos">837</span></a>                <span class="p">),</span>
+</span><span id="L-838"><a href="#L-838"><span class="linenos">838</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-839"><a href="#L-839"><span class="linenos">839</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="L-840"><a href="#L-840"><span class="linenos">840</span></a>                <span class="p">),</span>
+</span><span id="L-841"><a href="#L-841"><span class="linenos">841</span></a>            <span class="p">],</span>
+</span><span id="L-842"><a href="#L-842"><span class="linenos">842</span></a>            <span class="p">[</span>
+</span><span id="L-843"><a href="#L-843"><span class="linenos">843</span></a>                <span class="p">(</span>
+</span><span id="L-844"><a href="#L-844"><span class="linenos">844</span></a>                    <span class="p">[</span>
+</span><span id="L-845"><a href="#L-845"><span class="linenos">845</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-846"><a href="#L-846"><span class="linenos">846</span></a>                            <span class="p">{</span>
+</span><span id="L-847"><a href="#L-847"><span class="linenos">847</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-848"><a href="#L-848"><span class="linenos">848</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="L-849"><a href="#L-849"><span class="linenos">849</span></a>                            <span class="p">}</span>
+</span><span id="L-850"><a href="#L-850"><span class="linenos">850</span></a>                        <span class="p">)</span>
+</span><span id="L-851"><a href="#L-851"><span class="linenos">851</span></a>                    <span class="p">],</span>
+</span><span id="L-852"><a href="#L-852"><span class="linenos">852</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="L-853"><a href="#L-853"><span class="linenos">853</span></a>                <span class="p">),</span>
+</span><span id="L-854"><a href="#L-854"><span class="linenos">854</span></a>                <span class="p">(</span>
+</span><span id="L-855"><a href="#L-855"><span class="linenos">855</span></a>                    <span class="p">[</span>
+</span><span id="L-856"><a href="#L-856"><span class="linenos">856</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-857"><a href="#L-857"><span class="linenos">857</span></a>                            <span class="p">{</span>
+</span><span id="L-858"><a href="#L-858"><span class="linenos">858</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-859"><a href="#L-859"><span class="linenos">859</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="L-860"><a href="#L-860"><span class="linenos">860</span></a>                            <span class="p">}</span>
+</span><span id="L-861"><a href="#L-861"><span class="linenos">861</span></a>                        <span class="p">)</span>
+</span><span id="L-862"><a href="#L-862"><span class="linenos">862</span></a>                    <span class="p">],</span>
+</span><span id="L-863"><a href="#L-863"><span class="linenos">863</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="L-864"><a href="#L-864"><span class="linenos">864</span></a>                <span class="p">),</span>
+</span><span id="L-865"><a href="#L-865"><span class="linenos">865</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="L-866"><a href="#L-866"><span class="linenos">866</span></a>            <span class="p">],</span>
+</span><span id="L-867"><a href="#L-867"><span class="linenos">867</span></a>        <span class="p">)</span>
+</span><span id="L-868"><a href="#L-868"><span class="linenos">868</span></a>
+</span><span id="L-869"><a href="#L-869"><span class="linenos">869</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-870"><a href="#L-870"><span class="linenos">870</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-871"><a href="#L-871"><span class="linenos">871</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-872"><a href="#L-872"><span class="linenos">872</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-873"><a href="#L-873"><span class="linenos">873</span></a>                <span class="p">{</span>
+</span><span id="L-874"><a href="#L-874"><span class="linenos">874</span></a>                    <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="L-875"><a href="#L-875"><span class="linenos">875</span></a>                    <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="L-876"><a href="#L-876"><span class="linenos">876</span></a>                    <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="L-877"><a href="#L-877"><span class="linenos">877</span></a>                <span class="p">},</span>
+</span><span id="L-878"><a href="#L-878"><span class="linenos">878</span></a>            <span class="p">)</span>
+</span><span id="L-879"><a href="#L-879"><span class="linenos">879</span></a>        <span class="p">)</span>
+</span><span id="L-880"><a href="#L-880"><span class="linenos">880</span></a>
+</span><span id="L-881"><a href="#L-881"><span class="linenos">881</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-882"><a href="#L-882"><span class="linenos">882</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="L-883"><a href="#L-883"><span class="linenos">883</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="L-884"><a href="#L-884"><span class="linenos">884</span></a>
+</span><span id="L-885"><a href="#L-885"><span class="linenos">885</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-886"><a href="#L-886"><span class="linenos">886</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="L-887"><a href="#L-887"><span class="linenos">887</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="L-888"><a href="#L-888"><span class="linenos">888</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="L-889"><a href="#L-889"><span class="linenos">889</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="L-890"><a href="#L-890"><span class="linenos">890</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="L-891"><a href="#L-891"><span class="linenos">891</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="L-892"><a href="#L-892"><span class="linenos">892</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-893"><a href="#L-893"><span class="linenos">893</span></a>                <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-894"><a href="#L-894"><span class="linenos">894</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-895"><a href="#L-895"><span class="linenos">895</span></a>                    <span class="p">{</span>
+</span><span id="L-896"><a href="#L-896"><span class="linenos">896</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="L-897"><a href="#L-897"><span class="linenos">897</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="L-898"><a href="#L-898"><span class="linenos">898</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="L-899"><a href="#L-899"><span class="linenos">899</span></a>                    <span class="p">},</span>
+</span><span id="L-900"><a href="#L-900"><span class="linenos">900</span></a>                <span class="p">)</span>
+</span><span id="L-901"><a href="#L-901"><span class="linenos">901</span></a>            <span class="p">)</span>
+</span><span id="L-902"><a href="#L-902"><span class="linenos">902</span></a>
+</span><span id="L-903"><a href="#L-903"><span class="linenos">903</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-904"><a href="#L-904"><span class="linenos">904</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-905"><a href="#L-905"><span class="linenos">905</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="State">
+                            <input id="State-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">State</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="State-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#State"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="State-89"><a href="#State-89"><span class="linenos"> 89</span></a><span class="k">class</span><span class="w"> </span><span class="nc">State</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="State-90"><a href="#State-90"><span class="linenos"> 90</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Provide a Boolean state.</span>
+</span><span id="State-91"><a href="#State-91"><span class="linenos"> 91</span></a>
+</span><span id="State-92"><a href="#State-92"><span class="linenos"> 92</span></a><span class="sd">    The state of a State plugin instance can be queried with the &quot;get state&quot;</span>
+</span><span id="State-93"><a href="#State-93"><span class="linenos"> 93</span></a><span class="sd">    command and set with the &quot;set state&quot; command to the new state given by</span>
+</span><span id="State-94"><a href="#State-94"><span class="linenos"> 94</span></a><span class="sd">    the &quot;new state&quot; key:</span>
+</span><span id="State-95"><a href="#State-95"><span class="linenos"> 95</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="State-96"><a href="#State-96"><span class="linenos"> 96</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="State-97"><a href="#State-97"><span class="linenos"> 97</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="State-98"><a href="#State-98"><span class="linenos"> 98</span></a><span class="sd">    ...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;}},</span>
+</span><span id="State-99"><a href="#State-99"><span class="linenos"> 99</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="State-100"><a href="#State-100"><span class="linenos">100</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="State-101"><a href="#State-101"><span class="linenos">101</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="State-102"><a href="#State-102"><span class="linenos">102</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="State-103"><a href="#State-103"><span class="linenos">103</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="State-104"><a href="#State-104"><span class="linenos">104</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;}]))</span>
+</span><span id="State-105"><a href="#State-105"><span class="linenos">105</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="State-106"><a href="#State-106"><span class="linenos">106</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="State-107"><a href="#State-107"><span class="linenos">107</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="State-108"><a href="#State-108"><span class="linenos">108</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="State-109"><a href="#State-109"><span class="linenos">109</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="State-110"><a href="#State-110"><span class="linenos">110</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="State-111"><a href="#State-111"><span class="linenos">111</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>
+</span><span id="State-112"><a href="#State-112"><span class="linenos">112</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="State-113"><a href="#State-113"><span class="linenos">113</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="State-114"><a href="#State-114"><span class="linenos">114</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="State-115"><a href="#State-115"><span class="linenos">115</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="State-116"><a href="#State-116"><span class="linenos">116</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="State-117"><a href="#State-117"><span class="linenos">117</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</span><span id="State-118"><a href="#State-118"><span class="linenos">118</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</span><span id="State-119"><a href="#State-119"><span class="linenos">119</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="State-120"><a href="#State-120"><span class="linenos">120</span></a>
+</span><span id="State-121"><a href="#State-121"><span class="linenos">121</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="State-122"><a href="#State-122"><span class="linenos">122</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for State plugin configuration.</span>
+</span><span id="State-123"><a href="#State-123"><span class="linenos">123</span></a>
+</span><span id="State-124"><a href="#State-124"><span class="linenos">124</span></a><span class="sd">    There are no required or optional configuration keys.</span>
+</span><span id="State-125"><a href="#State-125"><span class="linenos">125</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="State-126"><a href="#State-126"><span class="linenos">126</span></a>
+</span><span id="State-127"><a href="#State-127"><span class="linenos">127</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="State-128"><a href="#State-128"><span class="linenos">128</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="State-129"><a href="#State-129"><span class="linenos">129</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="State-130"><a href="#State-130"><span class="linenos">130</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="State-131"><a href="#State-131"><span class="linenos">131</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="State-132"><a href="#State-132"><span class="linenos">132</span></a>            <span class="s2">&quot;State&quot;</span><span class="p">,</span>
+</span><span id="State-133"><a href="#State-133"><span class="linenos">133</span></a>            <span class="p">[</span>
+</span><span id="State-134"><a href="#State-134"><span class="linenos">134</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="State-135"><a href="#State-135"><span class="linenos">135</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="State-136"><a href="#State-136"><span class="linenos">136</span></a>                <span class="p">),</span>
+</span><span id="State-137"><a href="#State-137"><span class="linenos">137</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="State-138"><a href="#State-138"><span class="linenos">138</span></a>            <span class="p">],</span>
+</span><span id="State-139"><a href="#State-139"><span class="linenos">139</span></a>            <span class="p">[</span>
+</span><span id="State-140"><a href="#State-140"><span class="linenos">140</span></a>                <span class="p">(</span>
+</span><span id="State-141"><a href="#State-141"><span class="linenos">141</span></a>                    <span class="p">[</span>
+</span><span id="State-142"><a href="#State-142"><span class="linenos">142</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="State-143"><a href="#State-143"><span class="linenos">143</span></a>                            <span class="p">{</span>
+</span><span id="State-144"><a href="#State-144"><span class="linenos">144</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="State-145"><a href="#State-145"><span class="linenos">145</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="State-146"><a href="#State-146"><span class="linenos">146</span></a>                            <span class="p">}</span>
+</span><span id="State-147"><a href="#State-147"><span class="linenos">147</span></a>                        <span class="p">)</span>
+</span><span id="State-148"><a href="#State-148"><span class="linenos">148</span></a>                    <span class="p">],</span>
+</span><span id="State-149"><a href="#State-149"><span class="linenos">149</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="State-150"><a href="#State-150"><span class="linenos">150</span></a>                <span class="p">),</span>
+</span><span id="State-151"><a href="#State-151"><span class="linenos">151</span></a>                <span class="p">(</span>
+</span><span id="State-152"><a href="#State-152"><span class="linenos">152</span></a>                    <span class="p">[</span>
+</span><span id="State-153"><a href="#State-153"><span class="linenos">153</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="State-154"><a href="#State-154"><span class="linenos">154</span></a>                            <span class="p">{</span>
+</span><span id="State-155"><a href="#State-155"><span class="linenos">155</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="State-156"><a href="#State-156"><span class="linenos">156</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="State-157"><a href="#State-157"><span class="linenos">157</span></a>                                <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="State-158"><a href="#State-158"><span class="linenos">158</span></a>                            <span class="p">}</span>
+</span><span id="State-159"><a href="#State-159"><span class="linenos">159</span></a>                        <span class="p">)</span>
+</span><span id="State-160"><a href="#State-160"><span class="linenos">160</span></a>                    <span class="p">],</span>
+</span><span id="State-161"><a href="#State-161"><span class="linenos">161</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_state</span><span class="p">,</span>
+</span><span id="State-162"><a href="#State-162"><span class="linenos">162</span></a>                <span class="p">),</span>
+</span><span id="State-163"><a href="#State-163"><span class="linenos">163</span></a>            <span class="p">],</span>
+</span><span id="State-164"><a href="#State-164"><span class="linenos">164</span></a>        <span class="p">)</span>
+</span><span id="State-165"><a href="#State-165"><span class="linenos">165</span></a>
+</span><span id="State-166"><a href="#State-166"><span class="linenos">166</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="State-167"><a href="#State-167"><span class="linenos">167</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="State-168"><a href="#State-168"><span class="linenos">168</span></a>
+</span><span id="State-169"><a href="#State-169"><span class="linenos">169</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_set_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="State-170"><a href="#State-170"><span class="linenos">170</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">]:</span>
+</span><span id="State-171"><a href="#State-171"><span class="linenos">171</span></a>            <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="State-172"><a href="#State-172"><span class="linenos">172</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">]</span>
+</span><span id="State-173"><a href="#State-173"><span class="linenos">173</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="State-174"><a href="#State-174"><span class="linenos">174</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">,</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">})</span>
+</span><span id="State-175"><a href="#State-175"><span class="linenos">175</span></a>            <span class="p">)</span>
+</span><span id="State-176"><a href="#State-176"><span class="linenos">176</span></a>        <span class="k">else</span><span class="p">:</span>
+</span><span id="State-177"><a href="#State-177"><span class="linenos">177</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="State-178"><a href="#State-178"><span class="linenos">178</span></a>
+</span><span id="State-179"><a href="#State-179"><span class="linenos">179</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="State-180"><a href="#State-180"><span class="linenos">180</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="State-181"><a href="#State-181"><span class="linenos">181</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Provide a Boolean state.</p>
+
+<p>The state of a State plugin instance can be queried with the "get state"
+command and set with the "set state" command to the new state given by
+the "new state" key:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="State.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">True</span>
+
+        
+    </div>
+    <a class="headerlink" href="#State.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for State plugin configuration.</p>
+
+<p>There are no required or optional configuration keys.</p>
+</div>
+
+
+                            </div>
+                            <div id="State.process_conf" class="classattr">
+                                        <input id="State.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="State.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#State.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="State.process_conf-127"><a href="#State.process_conf-127"><span class="linenos">127</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="State.process_conf-128"><a href="#State.process_conf-128"><span class="linenos">128</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="State.process_conf-129"><a href="#State.process_conf-129"><span class="linenos">129</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="State.process_conf-130"><a href="#State.process_conf-130"><span class="linenos">130</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="State.process_conf-131"><a href="#State.process_conf-131"><span class="linenos">131</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="State.process_conf-132"><a href="#State.process_conf-132"><span class="linenos">132</span></a>            <span class="s2">&quot;State&quot;</span><span class="p">,</span>
+</span><span id="State.process_conf-133"><a href="#State.process_conf-133"><span class="linenos">133</span></a>            <span class="p">[</span>
+</span><span id="State.process_conf-134"><a href="#State.process_conf-134"><span class="linenos">134</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="State.process_conf-135"><a href="#State.process_conf-135"><span class="linenos">135</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="State.process_conf-136"><a href="#State.process_conf-136"><span class="linenos">136</span></a>                <span class="p">),</span>
+</span><span id="State.process_conf-137"><a href="#State.process_conf-137"><span class="linenos">137</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="State.process_conf-138"><a href="#State.process_conf-138"><span class="linenos">138</span></a>            <span class="p">],</span>
+</span><span id="State.process_conf-139"><a href="#State.process_conf-139"><span class="linenos">139</span></a>            <span class="p">[</span>
+</span><span id="State.process_conf-140"><a href="#State.process_conf-140"><span class="linenos">140</span></a>                <span class="p">(</span>
+</span><span id="State.process_conf-141"><a href="#State.process_conf-141"><span class="linenos">141</span></a>                    <span class="p">[</span>
+</span><span id="State.process_conf-142"><a href="#State.process_conf-142"><span class="linenos">142</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="State.process_conf-143"><a href="#State.process_conf-143"><span class="linenos">143</span></a>                            <span class="p">{</span>
+</span><span id="State.process_conf-144"><a href="#State.process_conf-144"><span class="linenos">144</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="State.process_conf-145"><a href="#State.process_conf-145"><span class="linenos">145</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="State.process_conf-146"><a href="#State.process_conf-146"><span class="linenos">146</span></a>                            <span class="p">}</span>
+</span><span id="State.process_conf-147"><a href="#State.process_conf-147"><span class="linenos">147</span></a>                        <span class="p">)</span>
+</span><span id="State.process_conf-148"><a href="#State.process_conf-148"><span class="linenos">148</span></a>                    <span class="p">],</span>
+</span><span id="State.process_conf-149"><a href="#State.process_conf-149"><span class="linenos">149</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="State.process_conf-150"><a href="#State.process_conf-150"><span class="linenos">150</span></a>                <span class="p">),</span>
+</span><span id="State.process_conf-151"><a href="#State.process_conf-151"><span class="linenos">151</span></a>                <span class="p">(</span>
+</span><span id="State.process_conf-152"><a href="#State.process_conf-152"><span class="linenos">152</span></a>                    <span class="p">[</span>
+</span><span id="State.process_conf-153"><a href="#State.process_conf-153"><span class="linenos">153</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="State.process_conf-154"><a href="#State.process_conf-154"><span class="linenos">154</span></a>                            <span class="p">{</span>
+</span><span id="State.process_conf-155"><a href="#State.process_conf-155"><span class="linenos">155</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="State.process_conf-156"><a href="#State.process_conf-156"><span class="linenos">156</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="State.process_conf-157"><a href="#State.process_conf-157"><span class="linenos">157</span></a>                                <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="State.process_conf-158"><a href="#State.process_conf-158"><span class="linenos">158</span></a>                            <span class="p">}</span>
+</span><span id="State.process_conf-159"><a href="#State.process_conf-159"><span class="linenos">159</span></a>                        <span class="p">)</span>
+</span><span id="State.process_conf-160"><a href="#State.process_conf-160"><span class="linenos">160</span></a>                    <span class="p">],</span>
+</span><span id="State.process_conf-161"><a href="#State.process_conf-161"><span class="linenos">161</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_state</span><span class="p">,</span>
+</span><span id="State.process_conf-162"><a href="#State.process_conf-162"><span class="linenos">162</span></a>                <span class="p">),</span>
+</span><span id="State.process_conf-163"><a href="#State.process_conf-163"><span class="linenos">163</span></a>            <span class="p">],</span>
+</span><span id="State.process_conf-164"><a href="#State.process_conf-164"><span class="linenos">164</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="State.run" class="classattr">
+                                        <input id="State.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="State.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#State.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="State.run-179"><a href="#State.run-179"><span class="linenos">179</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="State.run-180"><a href="#State.run-180"><span class="linenos">180</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="State.run-181"><a href="#State.run-181"><span class="linenos">181</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="State.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="State.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="State.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="State.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="StateAlias">
+                            <input id="StateAlias-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">StateAlias</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="StateAlias-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#StateAlias"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="StateAlias-184"><a href="#StateAlias-184"><span class="linenos">184</span></a><span class="k">class</span><span class="w"> </span><span class="nc">StateAlias</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="StateAlias-185"><a href="#StateAlias-185"><span class="linenos">185</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define an alias for another state.</span>
+</span><span id="StateAlias-186"><a href="#StateAlias-186"><span class="linenos">186</span></a>
+</span><span id="StateAlias-187"><a href="#StateAlias-187"><span class="linenos">187</span></a><span class="sd">    The &quot;alias for&quot; configuration key gets the name for the other state that</span>
+</span><span id="StateAlias-188"><a href="#StateAlias-188"><span class="linenos">188</span></a><span class="sd">    is aliased by the StateAlias plugin instance.</span>
+</span><span id="StateAlias-189"><a href="#StateAlias-189"><span class="linenos">189</span></a>
+</span><span id="StateAlias-190"><a href="#StateAlias-190"><span class="linenos">190</span></a><span class="sd">    The &quot;get state&quot; and &quot;set state&quot; commands are forwarded to and the</span>
+</span><span id="StateAlias-191"><a href="#StateAlias-191"><span class="linenos">191</span></a><span class="sd">    &quot;changed&quot; events and &quot;state&quot; messages are forwarded from this other</span>
+</span><span id="StateAlias-192"><a href="#StateAlias-192"><span class="linenos">192</span></a><span class="sd">    state:</span>
+</span><span id="StateAlias-193"><a href="#StateAlias-193"><span class="linenos">193</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="StateAlias-194"><a href="#StateAlias-194"><span class="linenos">194</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="StateAlias-195"><a href="#StateAlias-195"><span class="linenos">195</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="StateAlias-196"><a href="#StateAlias-196"><span class="linenos">196</span></a><span class="sd">    ...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="StateAlias-197"><a href="#StateAlias-197"><span class="linenos">197</span></a><span class="sd">    ...      &quot;Test StateAlias&quot;: {&quot;plugin&quot;: &quot;StateAlias&quot;,</span>
+</span><span id="StateAlias-198"><a href="#StateAlias-198"><span class="linenos">198</span></a><span class="sd">    ...                          &quot;alias for&quot;: &quot;Test State&quot;}},</span>
+</span><span id="StateAlias-199"><a href="#StateAlias-199"><span class="linenos">199</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="StateAlias-200"><a href="#StateAlias-200"><span class="linenos">200</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test StateAlias&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="StateAlias-201"><a href="#StateAlias-201"><span class="linenos">201</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="StateAlias-202"><a href="#StateAlias-202"><span class="linenos">202</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="StateAlias-203"><a href="#StateAlias-203"><span class="linenos">203</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="StateAlias-204"><a href="#StateAlias-204"><span class="linenos">204</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test StateAlias&quot;, &quot;command&quot;: &quot;get state&quot;}]))</span>
+</span><span id="StateAlias-205"><a href="#StateAlias-205"><span class="linenos">205</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="StateAlias-206"><a href="#StateAlias-206"><span class="linenos">206</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="StateAlias-207"><a href="#StateAlias-207"><span class="linenos">207</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="StateAlias-208"><a href="#StateAlias-208"><span class="linenos">208</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="StateAlias-209"><a href="#StateAlias-209"><span class="linenos">209</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+</span><span id="StateAlias-210"><a href="#StateAlias-210"><span class="linenos">210</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="StateAlias-211"><a href="#StateAlias-211"><span class="linenos">211</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>
+</span><span id="StateAlias-212"><a href="#StateAlias-212"><span class="linenos">212</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="StateAlias-213"><a href="#StateAlias-213"><span class="linenos">213</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="StateAlias-214"><a href="#StateAlias-214"><span class="linenos">214</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="StateAlias-215"><a href="#StateAlias-215"><span class="linenos">215</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="StateAlias-216"><a href="#StateAlias-216"><span class="linenos">216</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: False}</span>
+</span><span id="StateAlias-217"><a href="#StateAlias-217"><span class="linenos">217</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+</span><span id="StateAlias-218"><a href="#StateAlias-218"><span class="linenos">218</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="StateAlias-219"><a href="#StateAlias-219"><span class="linenos">219</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="StateAlias-220"><a href="#StateAlias-220"><span class="linenos">220</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+</span><span id="StateAlias-221"><a href="#StateAlias-221"><span class="linenos">221</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+</span><span id="StateAlias-222"><a href="#StateAlias-222"><span class="linenos">222</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="StateAlias-223"><a href="#StateAlias-223"><span class="linenos">223</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="StateAlias-224"><a href="#StateAlias-224"><span class="linenos">224</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}</span>
+</span><span id="StateAlias-225"><a href="#StateAlias-225"><span class="linenos">225</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="StateAlias-226"><a href="#StateAlias-226"><span class="linenos">226</span></a>
+</span><span id="StateAlias-227"><a href="#StateAlias-227"><span class="linenos">227</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="StateAlias-228"><a href="#StateAlias-228"><span class="linenos">228</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;alias for&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}},</span>
+</span><span id="StateAlias-229"><a href="#StateAlias-229"><span class="linenos">229</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">],</span>
+</span><span id="StateAlias-230"><a href="#StateAlias-230"><span class="linenos">230</span></a>    <span class="p">}</span>
+</span><span id="StateAlias-231"><a href="#StateAlias-231"><span class="linenos">231</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for StateAlias plugin configuration.</span>
+</span><span id="StateAlias-232"><a href="#StateAlias-232"><span class="linenos">232</span></a>
+</span><span id="StateAlias-233"><a href="#StateAlias-233"><span class="linenos">233</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="StateAlias-234"><a href="#StateAlias-234"><span class="linenos">234</span></a>
+</span><span id="StateAlias-235"><a href="#StateAlias-235"><span class="linenos">235</span></a><span class="sd">    - &#39;alias for&#39;: name of aliased state.</span>
+</span><span id="StateAlias-236"><a href="#StateAlias-236"><span class="linenos">236</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="StateAlias-237"><a href="#StateAlias-237"><span class="linenos">237</span></a>
+</span><span id="StateAlias-238"><a href="#StateAlias-238"><span class="linenos">238</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias-239"><a href="#StateAlias-239"><span class="linenos">239</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="StateAlias-240"><a href="#StateAlias-240"><span class="linenos">240</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="StateAlias-241"><a href="#StateAlias-241"><span class="linenos">241</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="StateAlias-242"><a href="#StateAlias-242"><span class="linenos">242</span></a>            <span class="s2">&quot;StateAlias&quot;</span><span class="p">,</span>
+</span><span id="StateAlias-243"><a href="#StateAlias-243"><span class="linenos">243</span></a>            <span class="p">[</span>
+</span><span id="StateAlias-244"><a href="#StateAlias-244"><span class="linenos">244</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias-245"><a href="#StateAlias-245"><span class="linenos">245</span></a>                    <span class="p">{</span>
+</span><span id="StateAlias-246"><a href="#StateAlias-246"><span class="linenos">246</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="StateAlias-247"><a href="#StateAlias-247"><span class="linenos">247</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-248"><a href="#StateAlias-248"><span class="linenos">248</span></a>                    <span class="p">}</span>
+</span><span id="StateAlias-249"><a href="#StateAlias-249"><span class="linenos">249</span></a>                <span class="p">),</span>
+</span><span id="StateAlias-250"><a href="#StateAlias-250"><span class="linenos">250</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias-251"><a href="#StateAlias-251"><span class="linenos">251</span></a>                    <span class="p">{</span>
+</span><span id="StateAlias-252"><a href="#StateAlias-252"><span class="linenos">252</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="StateAlias-253"><a href="#StateAlias-253"><span class="linenos">253</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-254"><a href="#StateAlias-254"><span class="linenos">254</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-255"><a href="#StateAlias-255"><span class="linenos">255</span></a>                    <span class="p">}</span>
+</span><span id="StateAlias-256"><a href="#StateAlias-256"><span class="linenos">256</span></a>                <span class="p">),</span>
+</span><span id="StateAlias-257"><a href="#StateAlias-257"><span class="linenos">257</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias-258"><a href="#StateAlias-258"><span class="linenos">258</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="StateAlias-259"><a href="#StateAlias-259"><span class="linenos">259</span></a>                <span class="p">),</span>
+</span><span id="StateAlias-260"><a href="#StateAlias-260"><span class="linenos">260</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="StateAlias-261"><a href="#StateAlias-261"><span class="linenos">261</span></a>            <span class="p">],</span>
+</span><span id="StateAlias-262"><a href="#StateAlias-262"><span class="linenos">262</span></a>            <span class="p">[</span>
+</span><span id="StateAlias-263"><a href="#StateAlias-263"><span class="linenos">263</span></a>                <span class="p">(</span>
+</span><span id="StateAlias-264"><a href="#StateAlias-264"><span class="linenos">264</span></a>                    <span class="p">[</span>
+</span><span id="StateAlias-265"><a href="#StateAlias-265"><span class="linenos">265</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias-266"><a href="#StateAlias-266"><span class="linenos">266</span></a>                            <span class="p">{</span>
+</span><span id="StateAlias-267"><a href="#StateAlias-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="StateAlias-268"><a href="#StateAlias-268"><span class="linenos">268</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-269"><a href="#StateAlias-269"><span class="linenos">269</span></a>                            <span class="p">}</span>
+</span><span id="StateAlias-270"><a href="#StateAlias-270"><span class="linenos">270</span></a>                        <span class="p">)</span>
+</span><span id="StateAlias-271"><a href="#StateAlias-271"><span class="linenos">271</span></a>                    <span class="p">],</span>
+</span><span id="StateAlias-272"><a href="#StateAlias-272"><span class="linenos">272</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="StateAlias-273"><a href="#StateAlias-273"><span class="linenos">273</span></a>                <span class="p">),</span>
+</span><span id="StateAlias-274"><a href="#StateAlias-274"><span class="linenos">274</span></a>                <span class="p">(</span>
+</span><span id="StateAlias-275"><a href="#StateAlias-275"><span class="linenos">275</span></a>                    <span class="p">[</span>
+</span><span id="StateAlias-276"><a href="#StateAlias-276"><span class="linenos">276</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias-277"><a href="#StateAlias-277"><span class="linenos">277</span></a>                            <span class="p">{</span>
+</span><span id="StateAlias-278"><a href="#StateAlias-278"><span class="linenos">278</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="StateAlias-279"><a href="#StateAlias-279"><span class="linenos">279</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-280"><a href="#StateAlias-280"><span class="linenos">280</span></a>                                <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-281"><a href="#StateAlias-281"><span class="linenos">281</span></a>                            <span class="p">}</span>
+</span><span id="StateAlias-282"><a href="#StateAlias-282"><span class="linenos">282</span></a>                        <span class="p">)</span>
+</span><span id="StateAlias-283"><a href="#StateAlias-283"><span class="linenos">283</span></a>                    <span class="p">],</span>
+</span><span id="StateAlias-284"><a href="#StateAlias-284"><span class="linenos">284</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_state</span><span class="p">,</span>
+</span><span id="StateAlias-285"><a href="#StateAlias-285"><span class="linenos">285</span></a>                <span class="p">),</span>
+</span><span id="StateAlias-286"><a href="#StateAlias-286"><span class="linenos">286</span></a>                <span class="p">(</span>
+</span><span id="StateAlias-287"><a href="#StateAlias-287"><span class="linenos">287</span></a>                    <span class="p">[</span>
+</span><span id="StateAlias-288"><a href="#StateAlias-288"><span class="linenos">288</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias-289"><a href="#StateAlias-289"><span class="linenos">289</span></a>                            <span class="p">{</span>
+</span><span id="StateAlias-290"><a href="#StateAlias-290"><span class="linenos">290</span></a>                                <span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="StateAlias-291"><a href="#StateAlias-291"><span class="linenos">291</span></a>                                <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="StateAlias-292"><a href="#StateAlias-292"><span class="linenos">292</span></a>                            <span class="p">}</span>
+</span><span id="StateAlias-293"><a href="#StateAlias-293"><span class="linenos">293</span></a>                        <span class="p">)</span>
+</span><span id="StateAlias-294"><a href="#StateAlias-294"><span class="linenos">294</span></a>                    <span class="p">],</span>
+</span><span id="StateAlias-295"><a href="#StateAlias-295"><span class="linenos">295</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">,</span>
+</span><span id="StateAlias-296"><a href="#StateAlias-296"><span class="linenos">296</span></a>                <span class="p">),</span>
+</span><span id="StateAlias-297"><a href="#StateAlias-297"><span class="linenos">297</span></a>            <span class="p">],</span>
+</span><span id="StateAlias-298"><a href="#StateAlias-298"><span class="linenos">298</span></a>        <span class="p">)</span>
+</span><span id="StateAlias-299"><a href="#StateAlias-299"><span class="linenos">299</span></a>
+</span><span id="StateAlias-300"><a href="#StateAlias-300"><span class="linenos">300</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias-301"><a href="#StateAlias-301"><span class="linenos">301</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="StateAlias-302"><a href="#StateAlias-302"><span class="linenos">302</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="StateAlias-303"><a href="#StateAlias-303"><span class="linenos">303</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">],</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">}</span>
+</span><span id="StateAlias-304"><a href="#StateAlias-304"><span class="linenos">304</span></a>            <span class="p">)</span>
+</span><span id="StateAlias-305"><a href="#StateAlias-305"><span class="linenos">305</span></a>        <span class="p">)</span>
+</span><span id="StateAlias-306"><a href="#StateAlias-306"><span class="linenos">306</span></a>
+</span><span id="StateAlias-307"><a href="#StateAlias-307"><span class="linenos">307</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_set_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias-308"><a href="#StateAlias-308"><span class="linenos">308</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="StateAlias-309"><a href="#StateAlias-309"><span class="linenos">309</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="StateAlias-310"><a href="#StateAlias-310"><span class="linenos">310</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="StateAlias-311"><a href="#StateAlias-311"><span class="linenos">311</span></a>                <span class="p">{</span>
+</span><span id="StateAlias-312"><a href="#StateAlias-312"><span class="linenos">312</span></a>                    <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">],</span>
+</span><span id="StateAlias-313"><a href="#StateAlias-313"><span class="linenos">313</span></a>                    <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="StateAlias-314"><a href="#StateAlias-314"><span class="linenos">314</span></a>                    <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;new state&quot;</span><span class="p">],</span>
+</span><span id="StateAlias-315"><a href="#StateAlias-315"><span class="linenos">315</span></a>                <span class="p">},</span>
+</span><span id="StateAlias-316"><a href="#StateAlias-316"><span class="linenos">316</span></a>            <span class="p">)</span>
+</span><span id="StateAlias-317"><a href="#StateAlias-317"><span class="linenos">317</span></a>        <span class="p">)</span>
+</span><span id="StateAlias-318"><a href="#StateAlias-318"><span class="linenos">318</span></a>
+</span><span id="StateAlias-319"><a href="#StateAlias-319"><span class="linenos">319</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_translate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias-320"><a href="#StateAlias-320"><span class="linenos">320</span></a>        <span class="n">alias_message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+</span><span id="StateAlias-321"><a href="#StateAlias-321"><span class="linenos">321</span></a>        <span class="k">if</span> <span class="s2">&quot;event&quot;</span> <span class="ow">in</span> <span class="n">message</span> <span class="ow">and</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;changed&quot;</span><span class="p">:</span>
+</span><span id="StateAlias-322"><a href="#StateAlias-322"><span class="linenos">322</span></a>            <span class="n">alias_message</span><span class="p">[</span><span class="s2">&quot;event&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;changed&quot;</span>
+</span><span id="StateAlias-323"><a href="#StateAlias-323"><span class="linenos">323</span></a>        <span class="n">alias_message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="StateAlias-324"><a href="#StateAlias-324"><span class="linenos">324</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">alias_message</span><span class="p">)</span>
+</span><span id="StateAlias-325"><a href="#StateAlias-325"><span class="linenos">325</span></a>
+</span><span id="StateAlias-326"><a href="#StateAlias-326"><span class="linenos">326</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias-327"><a href="#StateAlias-327"><span class="linenos">327</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="StateAlias-328"><a href="#StateAlias-328"><span class="linenos">328</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Define an alias for another state.</p>
+
+<p>The "alias for" configuration key gets the name for the other state that
+is aliased by the StateAlias plugin instance.</p>
+
+<p>The "get state" and "set state" commands are forwarded to and the
+"changed" events and "state" messages are forwarded from this other
+state:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;StateAlias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                         <span class="s2">&quot;alias for&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test StateAlias&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="StateAlias.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;alias for&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;required&#39;: [&#39;alias for&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#StateAlias.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for StateAlias plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'alias for': name of aliased state.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="StateAlias.process_conf" class="classattr">
+                                        <input id="StateAlias.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="StateAlias.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#StateAlias.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="StateAlias.process_conf-238"><a href="#StateAlias.process_conf-238"><span class="linenos">238</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias.process_conf-239"><a href="#StateAlias.process_conf-239"><span class="linenos">239</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="StateAlias.process_conf-240"><a href="#StateAlias.process_conf-240"><span class="linenos">240</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-241"><a href="#StateAlias.process_conf-241"><span class="linenos">241</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="StateAlias.process_conf-242"><a href="#StateAlias.process_conf-242"><span class="linenos">242</span></a>            <span class="s2">&quot;StateAlias&quot;</span><span class="p">,</span>
+</span><span id="StateAlias.process_conf-243"><a href="#StateAlias.process_conf-243"><span class="linenos">243</span></a>            <span class="p">[</span>
+</span><span id="StateAlias.process_conf-244"><a href="#StateAlias.process_conf-244"><span class="linenos">244</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-245"><a href="#StateAlias.process_conf-245"><span class="linenos">245</span></a>                    <span class="p">{</span>
+</span><span id="StateAlias.process_conf-246"><a href="#StateAlias.process_conf-246"><span class="linenos">246</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="StateAlias.process_conf-247"><a href="#StateAlias.process_conf-247"><span class="linenos">247</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-248"><a href="#StateAlias.process_conf-248"><span class="linenos">248</span></a>                    <span class="p">}</span>
+</span><span id="StateAlias.process_conf-249"><a href="#StateAlias.process_conf-249"><span class="linenos">249</span></a>                <span class="p">),</span>
+</span><span id="StateAlias.process_conf-250"><a href="#StateAlias.process_conf-250"><span class="linenos">250</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-251"><a href="#StateAlias.process_conf-251"><span class="linenos">251</span></a>                    <span class="p">{</span>
+</span><span id="StateAlias.process_conf-252"><a href="#StateAlias.process_conf-252"><span class="linenos">252</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="StateAlias.process_conf-253"><a href="#StateAlias.process_conf-253"><span class="linenos">253</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-254"><a href="#StateAlias.process_conf-254"><span class="linenos">254</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-255"><a href="#StateAlias.process_conf-255"><span class="linenos">255</span></a>                    <span class="p">}</span>
+</span><span id="StateAlias.process_conf-256"><a href="#StateAlias.process_conf-256"><span class="linenos">256</span></a>                <span class="p">),</span>
+</span><span id="StateAlias.process_conf-257"><a href="#StateAlias.process_conf-257"><span class="linenos">257</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-258"><a href="#StateAlias.process_conf-258"><span class="linenos">258</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="StateAlias.process_conf-259"><a href="#StateAlias.process_conf-259"><span class="linenos">259</span></a>                <span class="p">),</span>
+</span><span id="StateAlias.process_conf-260"><a href="#StateAlias.process_conf-260"><span class="linenos">260</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="StateAlias.process_conf-261"><a href="#StateAlias.process_conf-261"><span class="linenos">261</span></a>            <span class="p">],</span>
+</span><span id="StateAlias.process_conf-262"><a href="#StateAlias.process_conf-262"><span class="linenos">262</span></a>            <span class="p">[</span>
+</span><span id="StateAlias.process_conf-263"><a href="#StateAlias.process_conf-263"><span class="linenos">263</span></a>                <span class="p">(</span>
+</span><span id="StateAlias.process_conf-264"><a href="#StateAlias.process_conf-264"><span class="linenos">264</span></a>                    <span class="p">[</span>
+</span><span id="StateAlias.process_conf-265"><a href="#StateAlias.process_conf-265"><span class="linenos">265</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-266"><a href="#StateAlias.process_conf-266"><span class="linenos">266</span></a>                            <span class="p">{</span>
+</span><span id="StateAlias.process_conf-267"><a href="#StateAlias.process_conf-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-268"><a href="#StateAlias.process_conf-268"><span class="linenos">268</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-269"><a href="#StateAlias.process_conf-269"><span class="linenos">269</span></a>                            <span class="p">}</span>
+</span><span id="StateAlias.process_conf-270"><a href="#StateAlias.process_conf-270"><span class="linenos">270</span></a>                        <span class="p">)</span>
+</span><span id="StateAlias.process_conf-271"><a href="#StateAlias.process_conf-271"><span class="linenos">271</span></a>                    <span class="p">],</span>
+</span><span id="StateAlias.process_conf-272"><a href="#StateAlias.process_conf-272"><span class="linenos">272</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="StateAlias.process_conf-273"><a href="#StateAlias.process_conf-273"><span class="linenos">273</span></a>                <span class="p">),</span>
+</span><span id="StateAlias.process_conf-274"><a href="#StateAlias.process_conf-274"><span class="linenos">274</span></a>                <span class="p">(</span>
+</span><span id="StateAlias.process_conf-275"><a href="#StateAlias.process_conf-275"><span class="linenos">275</span></a>                    <span class="p">[</span>
+</span><span id="StateAlias.process_conf-276"><a href="#StateAlias.process_conf-276"><span class="linenos">276</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-277"><a href="#StateAlias.process_conf-277"><span class="linenos">277</span></a>                            <span class="p">{</span>
+</span><span id="StateAlias.process_conf-278"><a href="#StateAlias.process_conf-278"><span class="linenos">278</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-279"><a href="#StateAlias.process_conf-279"><span class="linenos">279</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-280"><a href="#StateAlias.process_conf-280"><span class="linenos">280</span></a>                                <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-281"><a href="#StateAlias.process_conf-281"><span class="linenos">281</span></a>                            <span class="p">}</span>
+</span><span id="StateAlias.process_conf-282"><a href="#StateAlias.process_conf-282"><span class="linenos">282</span></a>                        <span class="p">)</span>
+</span><span id="StateAlias.process_conf-283"><a href="#StateAlias.process_conf-283"><span class="linenos">283</span></a>                    <span class="p">],</span>
+</span><span id="StateAlias.process_conf-284"><a href="#StateAlias.process_conf-284"><span class="linenos">284</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_state</span><span class="p">,</span>
+</span><span id="StateAlias.process_conf-285"><a href="#StateAlias.process_conf-285"><span class="linenos">285</span></a>                <span class="p">),</span>
+</span><span id="StateAlias.process_conf-286"><a href="#StateAlias.process_conf-286"><span class="linenos">286</span></a>                <span class="p">(</span>
+</span><span id="StateAlias.process_conf-287"><a href="#StateAlias.process_conf-287"><span class="linenos">287</span></a>                    <span class="p">[</span>
+</span><span id="StateAlias.process_conf-288"><a href="#StateAlias.process_conf-288"><span class="linenos">288</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="StateAlias.process_conf-289"><a href="#StateAlias.process_conf-289"><span class="linenos">289</span></a>                            <span class="p">{</span>
+</span><span id="StateAlias.process_conf-290"><a href="#StateAlias.process_conf-290"><span class="linenos">290</span></a>                                <span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;alias for&quot;</span><span class="p">]},</span>
+</span><span id="StateAlias.process_conf-291"><a href="#StateAlias.process_conf-291"><span class="linenos">291</span></a>                                <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="StateAlias.process_conf-292"><a href="#StateAlias.process_conf-292"><span class="linenos">292</span></a>                            <span class="p">}</span>
+</span><span id="StateAlias.process_conf-293"><a href="#StateAlias.process_conf-293"><span class="linenos">293</span></a>                        <span class="p">)</span>
+</span><span id="StateAlias.process_conf-294"><a href="#StateAlias.process_conf-294"><span class="linenos">294</span></a>                    <span class="p">],</span>
+</span><span id="StateAlias.process_conf-295"><a href="#StateAlias.process_conf-295"><span class="linenos">295</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">,</span>
+</span><span id="StateAlias.process_conf-296"><a href="#StateAlias.process_conf-296"><span class="linenos">296</span></a>                <span class="p">),</span>
+</span><span id="StateAlias.process_conf-297"><a href="#StateAlias.process_conf-297"><span class="linenos">297</span></a>            <span class="p">],</span>
+</span><span id="StateAlias.process_conf-298"><a href="#StateAlias.process_conf-298"><span class="linenos">298</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="StateAlias.run" class="classattr">
+                                        <input id="StateAlias.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="StateAlias.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#StateAlias.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="StateAlias.run-326"><a href="#StateAlias.run-326"><span class="linenos">326</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="StateAlias.run-327"><a href="#StateAlias.run-327"><span class="linenos">327</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="StateAlias.run-328"><a href="#StateAlias.run-328"><span class="linenos">328</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="StateAlias.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="StateAlias.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="StateAlias.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="StateAlias.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="AndState">
+                            <input id="AndState-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">AndState</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="AndState-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#AndState"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="AndState-331"><a href="#AndState-331"><span class="linenos">331</span></a><span class="k">class</span><span class="w"> </span><span class="nc">AndState</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="AndState-332"><a href="#AndState-332"><span class="linenos">332</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define conjunction of states.</span>
+</span><span id="AndState-333"><a href="#AndState-333"><span class="linenos">333</span></a>
+</span><span id="AndState-334"><a href="#AndState-334"><span class="linenos">334</span></a><span class="sd">    The &quot;states&quot; configuration key gets an array of states to be combined.</span>
+</span><span id="AndState-335"><a href="#AndState-335"><span class="linenos">335</span></a><span class="sd">    An AndState plugin client reacts to &quot;get state&quot; commands and sends</span>
+</span><span id="AndState-336"><a href="#AndState-336"><span class="linenos">336</span></a><span class="sd">    &quot;changed&quot; events when a change in one of the combined states leads to</span>
+</span><span id="AndState-337"><a href="#AndState-337"><span class="linenos">337</span></a><span class="sd">    a change for the conjunction:</span>
+</span><span id="AndState-338"><a href="#AndState-338"><span class="linenos">338</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="AndState-339"><a href="#AndState-339"><span class="linenos">339</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="AndState-340"><a href="#AndState-340"><span class="linenos">340</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="AndState-341"><a href="#AndState-341"><span class="linenos">341</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="AndState-342"><a href="#AndState-342"><span class="linenos">342</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="AndState-343"><a href="#AndState-343"><span class="linenos">343</span></a><span class="sd">    ...      &quot;Test AndState&quot;: {&quot;plugin&quot;: &quot;AndState&quot;,</span>
+</span><span id="AndState-344"><a href="#AndState-344"><span class="linenos">344</span></a><span class="sd">    ...                        &quot;states&quot;: [&quot;Test State 1&quot;, &quot;Test State 2&quot;]}},</span>
+</span><span id="AndState-345"><a href="#AndState-345"><span class="linenos">345</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="AndState-346"><a href="#AndState-346"><span class="linenos">346</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="AndState-347"><a href="#AndState-347"><span class="linenos">347</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="AndState-348"><a href="#AndState-348"><span class="linenos">348</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="AndState-349"><a href="#AndState-349"><span class="linenos">349</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="AndState-350"><a href="#AndState-350"><span class="linenos">350</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="AndState-351"><a href="#AndState-351"><span class="linenos">351</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndState&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="AndState-352"><a href="#AndState-352"><span class="linenos">352</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndState&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="AndState-353"><a href="#AndState-353"><span class="linenos">353</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="AndState-354"><a href="#AndState-354"><span class="linenos">354</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="AndState-355"><a href="#AndState-355"><span class="linenos">355</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="AndState-356"><a href="#AndState-356"><span class="linenos">356</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="AndState-357"><a href="#AndState-357"><span class="linenos">357</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="AndState-358"><a href="#AndState-358"><span class="linenos">358</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="AndState-359"><a href="#AndState-359"><span class="linenos">359</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndState-360"><a href="#AndState-360"><span class="linenos">360</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="AndState-361"><a href="#AndState-361"><span class="linenos">361</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="AndState-362"><a href="#AndState-362"><span class="linenos">362</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndState-363"><a href="#AndState-363"><span class="linenos">363</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>
+</span><span id="AndState-364"><a href="#AndState-364"><span class="linenos">364</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="AndState-365"><a href="#AndState-365"><span class="linenos">365</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="AndState-366"><a href="#AndState-366"><span class="linenos">366</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndState-367"><a href="#AndState-367"><span class="linenos">367</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>
+</span><span id="AndState-368"><a href="#AndState-368"><span class="linenos">368</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="AndState-369"><a href="#AndState-369"><span class="linenos">369</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndState-370"><a href="#AndState-370"><span class="linenos">370</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="AndState-371"><a href="#AndState-371"><span class="linenos">371</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndState&#39;,</span>
+</span><span id="AndState-372"><a href="#AndState-372"><span class="linenos">372</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="AndState-373"><a href="#AndState-373"><span class="linenos">373</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="AndState-374"><a href="#AndState-374"><span class="linenos">374</span></a>
+</span><span id="AndState-375"><a href="#AndState-375"><span class="linenos">375</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="AndState-376"><a href="#AndState-376"><span class="linenos">376</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}},</span>
+</span><span id="AndState-377"><a href="#AndState-377"><span class="linenos">377</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">],</span>
+</span><span id="AndState-378"><a href="#AndState-378"><span class="linenos">378</span></a>    <span class="p">}</span>
+</span><span id="AndState-379"><a href="#AndState-379"><span class="linenos">379</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for AndState plugin configuration.</span>
+</span><span id="AndState-380"><a href="#AndState-380"><span class="linenos">380</span></a>
+</span><span id="AndState-381"><a href="#AndState-381"><span class="linenos">381</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="AndState-382"><a href="#AndState-382"><span class="linenos">382</span></a>
+</span><span id="AndState-383"><a href="#AndState-383"><span class="linenos">383</span></a><span class="sd">    - &#39;states&#39;: list of names of combined states.</span>
+</span><span id="AndState-384"><a href="#AndState-384"><span class="linenos">384</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="AndState-385"><a href="#AndState-385"><span class="linenos">385</span></a>
+</span><span id="AndState-386"><a href="#AndState-386"><span class="linenos">386</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState-387"><a href="#AndState-387"><span class="linenos">387</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="AndState-388"><a href="#AndState-388"><span class="linenos">388</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="AndState-389"><a href="#AndState-389"><span class="linenos">389</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="AndState-390"><a href="#AndState-390"><span class="linenos">390</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">]:</span>
+</span><span id="AndState-391"><a href="#AndState-391"><span class="linenos">391</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="AndState-392"><a href="#AndState-392"><span class="linenos">392</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState-393"><a href="#AndState-393"><span class="linenos">393</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="AndState-394"><a href="#AndState-394"><span class="linenos">394</span></a>                <span class="p">)</span>
+</span><span id="AndState-395"><a href="#AndState-395"><span class="linenos">395</span></a>            <span class="p">)</span>
+</span><span id="AndState-396"><a href="#AndState-396"><span class="linenos">396</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="AndState-397"><a href="#AndState-397"><span class="linenos">397</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="AndState-398"><a href="#AndState-398"><span class="linenos">398</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="AndState-399"><a href="#AndState-399"><span class="linenos">399</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="AndState-400"><a href="#AndState-400"><span class="linenos">400</span></a>            <span class="s2">&quot;AndState&quot;</span><span class="p">,</span>
+</span><span id="AndState-401"><a href="#AndState-401"><span class="linenos">401</span></a>            <span class="p">[</span>
+</span><span id="AndState-402"><a href="#AndState-402"><span class="linenos">402</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState-403"><a href="#AndState-403"><span class="linenos">403</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="AndState-404"><a href="#AndState-404"><span class="linenos">404</span></a>                <span class="p">),</span>
+</span><span id="AndState-405"><a href="#AndState-405"><span class="linenos">405</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="AndState-406"><a href="#AndState-406"><span class="linenos">406</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState-407"><a href="#AndState-407"><span class="linenos">407</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="AndState-408"><a href="#AndState-408"><span class="linenos">408</span></a>                <span class="p">),</span>
+</span><span id="AndState-409"><a href="#AndState-409"><span class="linenos">409</span></a>            <span class="p">],</span>
+</span><span id="AndState-410"><a href="#AndState-410"><span class="linenos">410</span></a>            <span class="p">[</span>
+</span><span id="AndState-411"><a href="#AndState-411"><span class="linenos">411</span></a>                <span class="p">(</span>
+</span><span id="AndState-412"><a href="#AndState-412"><span class="linenos">412</span></a>                    <span class="p">[</span>
+</span><span id="AndState-413"><a href="#AndState-413"><span class="linenos">413</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState-414"><a href="#AndState-414"><span class="linenos">414</span></a>                            <span class="p">{</span>
+</span><span id="AndState-415"><a href="#AndState-415"><span class="linenos">415</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndState-416"><a href="#AndState-416"><span class="linenos">416</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="AndState-417"><a href="#AndState-417"><span class="linenos">417</span></a>                            <span class="p">}</span>
+</span><span id="AndState-418"><a href="#AndState-418"><span class="linenos">418</span></a>                        <span class="p">)</span>
+</span><span id="AndState-419"><a href="#AndState-419"><span class="linenos">419</span></a>                    <span class="p">],</span>
+</span><span id="AndState-420"><a href="#AndState-420"><span class="linenos">420</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="AndState-421"><a href="#AndState-421"><span class="linenos">421</span></a>                <span class="p">),</span>
+</span><span id="AndState-422"><a href="#AndState-422"><span class="linenos">422</span></a>                <span class="p">(</span>
+</span><span id="AndState-423"><a href="#AndState-423"><span class="linenos">423</span></a>                    <span class="p">[</span>
+</span><span id="AndState-424"><a href="#AndState-424"><span class="linenos">424</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState-425"><a href="#AndState-425"><span class="linenos">425</span></a>                            <span class="p">{</span>
+</span><span id="AndState-426"><a href="#AndState-426"><span class="linenos">426</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndState-427"><a href="#AndState-427"><span class="linenos">427</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="AndState-428"><a href="#AndState-428"><span class="linenos">428</span></a>                            <span class="p">}</span>
+</span><span id="AndState-429"><a href="#AndState-429"><span class="linenos">429</span></a>                        <span class="p">)</span>
+</span><span id="AndState-430"><a href="#AndState-430"><span class="linenos">430</span></a>                    <span class="p">],</span>
+</span><span id="AndState-431"><a href="#AndState-431"><span class="linenos">431</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="AndState-432"><a href="#AndState-432"><span class="linenos">432</span></a>                <span class="p">),</span>
+</span><span id="AndState-433"><a href="#AndState-433"><span class="linenos">433</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="AndState-434"><a href="#AndState-434"><span class="linenos">434</span></a>            <span class="p">],</span>
+</span><span id="AndState-435"><a href="#AndState-435"><span class="linenos">435</span></a>        <span class="p">)</span>
+</span><span id="AndState-436"><a href="#AndState-436"><span class="linenos">436</span></a>
+</span><span id="AndState-437"><a href="#AndState-437"><span class="linenos">437</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState-438"><a href="#AndState-438"><span class="linenos">438</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="AndState-439"><a href="#AndState-439"><span class="linenos">439</span></a>
+</span><span id="AndState-440"><a href="#AndState-440"><span class="linenos">440</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState-441"><a href="#AndState-441"><span class="linenos">441</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="AndState-442"><a href="#AndState-442"><span class="linenos">442</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="AndState-443"><a href="#AndState-443"><span class="linenos">443</span></a>
+</span><span id="AndState-444"><a href="#AndState-444"><span class="linenos">444</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState-445"><a href="#AndState-445"><span class="linenos">445</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="AndState-446"><a href="#AndState-446"><span class="linenos">446</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="AndState-447"><a href="#AndState-447"><span class="linenos">447</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="AndState-448"><a href="#AndState-448"><span class="linenos">448</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="AndState-449"><a href="#AndState-449"><span class="linenos">449</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="AndState-450"><a href="#AndState-450"><span class="linenos">450</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="AndState-451"><a href="#AndState-451"><span class="linenos">451</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="AndState-452"><a href="#AndState-452"><span class="linenos">452</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">,</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">})</span>
+</span><span id="AndState-453"><a href="#AndState-453"><span class="linenos">453</span></a>            <span class="p">)</span>
+</span><span id="AndState-454"><a href="#AndState-454"><span class="linenos">454</span></a>
+</span><span id="AndState-455"><a href="#AndState-455"><span class="linenos">455</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState-456"><a href="#AndState-456"><span class="linenos">456</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="AndState-457"><a href="#AndState-457"><span class="linenos">457</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Define conjunction of states.</p>
+
+<p>The "states" configuration key gets an array of states to be combined.
+An AndState plugin client reacts to "get state" commands and sends
+"changed" events when a change in one of the combined states leads to
+a change for the conjunction:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 2&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test AndState&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;AndState&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                       <span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test AndState&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test AndState&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get sources&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndState&#39;,</span>
+<span class="go">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="AndState.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;states&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}}, &#39;required&#39;: [&#39;states&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#AndState.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for AndState plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'states': list of names of combined states.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="AndState.process_conf" class="classattr">
+                                        <input id="AndState.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="AndState.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#AndState.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="AndState.process_conf-386"><a href="#AndState.process_conf-386"><span class="linenos">386</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState.process_conf-387"><a href="#AndState.process_conf-387"><span class="linenos">387</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="AndState.process_conf-388"><a href="#AndState.process_conf-388"><span class="linenos">388</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="AndState.process_conf-389"><a href="#AndState.process_conf-389"><span class="linenos">389</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="AndState.process_conf-390"><a href="#AndState.process_conf-390"><span class="linenos">390</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">]:</span>
+</span><span id="AndState.process_conf-391"><a href="#AndState.process_conf-391"><span class="linenos">391</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="AndState.process_conf-392"><a href="#AndState.process_conf-392"><span class="linenos">392</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState.process_conf-393"><a href="#AndState.process_conf-393"><span class="linenos">393</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="AndState.process_conf-394"><a href="#AndState.process_conf-394"><span class="linenos">394</span></a>                <span class="p">)</span>
+</span><span id="AndState.process_conf-395"><a href="#AndState.process_conf-395"><span class="linenos">395</span></a>            <span class="p">)</span>
+</span><span id="AndState.process_conf-396"><a href="#AndState.process_conf-396"><span class="linenos">396</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="AndState.process_conf-397"><a href="#AndState.process_conf-397"><span class="linenos">397</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="AndState.process_conf-398"><a href="#AndState.process_conf-398"><span class="linenos">398</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="AndState.process_conf-399"><a href="#AndState.process_conf-399"><span class="linenos">399</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="AndState.process_conf-400"><a href="#AndState.process_conf-400"><span class="linenos">400</span></a>            <span class="s2">&quot;AndState&quot;</span><span class="p">,</span>
+</span><span id="AndState.process_conf-401"><a href="#AndState.process_conf-401"><span class="linenos">401</span></a>            <span class="p">[</span>
+</span><span id="AndState.process_conf-402"><a href="#AndState.process_conf-402"><span class="linenos">402</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState.process_conf-403"><a href="#AndState.process_conf-403"><span class="linenos">403</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="AndState.process_conf-404"><a href="#AndState.process_conf-404"><span class="linenos">404</span></a>                <span class="p">),</span>
+</span><span id="AndState.process_conf-405"><a href="#AndState.process_conf-405"><span class="linenos">405</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="AndState.process_conf-406"><a href="#AndState.process_conf-406"><span class="linenos">406</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState.process_conf-407"><a href="#AndState.process_conf-407"><span class="linenos">407</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="AndState.process_conf-408"><a href="#AndState.process_conf-408"><span class="linenos">408</span></a>                <span class="p">),</span>
+</span><span id="AndState.process_conf-409"><a href="#AndState.process_conf-409"><span class="linenos">409</span></a>            <span class="p">],</span>
+</span><span id="AndState.process_conf-410"><a href="#AndState.process_conf-410"><span class="linenos">410</span></a>            <span class="p">[</span>
+</span><span id="AndState.process_conf-411"><a href="#AndState.process_conf-411"><span class="linenos">411</span></a>                <span class="p">(</span>
+</span><span id="AndState.process_conf-412"><a href="#AndState.process_conf-412"><span class="linenos">412</span></a>                    <span class="p">[</span>
+</span><span id="AndState.process_conf-413"><a href="#AndState.process_conf-413"><span class="linenos">413</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState.process_conf-414"><a href="#AndState.process_conf-414"><span class="linenos">414</span></a>                            <span class="p">{</span>
+</span><span id="AndState.process_conf-415"><a href="#AndState.process_conf-415"><span class="linenos">415</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndState.process_conf-416"><a href="#AndState.process_conf-416"><span class="linenos">416</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="AndState.process_conf-417"><a href="#AndState.process_conf-417"><span class="linenos">417</span></a>                            <span class="p">}</span>
+</span><span id="AndState.process_conf-418"><a href="#AndState.process_conf-418"><span class="linenos">418</span></a>                        <span class="p">)</span>
+</span><span id="AndState.process_conf-419"><a href="#AndState.process_conf-419"><span class="linenos">419</span></a>                    <span class="p">],</span>
+</span><span id="AndState.process_conf-420"><a href="#AndState.process_conf-420"><span class="linenos">420</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="AndState.process_conf-421"><a href="#AndState.process_conf-421"><span class="linenos">421</span></a>                <span class="p">),</span>
+</span><span id="AndState.process_conf-422"><a href="#AndState.process_conf-422"><span class="linenos">422</span></a>                <span class="p">(</span>
+</span><span id="AndState.process_conf-423"><a href="#AndState.process_conf-423"><span class="linenos">423</span></a>                    <span class="p">[</span>
+</span><span id="AndState.process_conf-424"><a href="#AndState.process_conf-424"><span class="linenos">424</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndState.process_conf-425"><a href="#AndState.process_conf-425"><span class="linenos">425</span></a>                            <span class="p">{</span>
+</span><span id="AndState.process_conf-426"><a href="#AndState.process_conf-426"><span class="linenos">426</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndState.process_conf-427"><a href="#AndState.process_conf-427"><span class="linenos">427</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="AndState.process_conf-428"><a href="#AndState.process_conf-428"><span class="linenos">428</span></a>                            <span class="p">}</span>
+</span><span id="AndState.process_conf-429"><a href="#AndState.process_conf-429"><span class="linenos">429</span></a>                        <span class="p">)</span>
+</span><span id="AndState.process_conf-430"><a href="#AndState.process_conf-430"><span class="linenos">430</span></a>                    <span class="p">],</span>
+</span><span id="AndState.process_conf-431"><a href="#AndState.process_conf-431"><span class="linenos">431</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="AndState.process_conf-432"><a href="#AndState.process_conf-432"><span class="linenos">432</span></a>                <span class="p">),</span>
+</span><span id="AndState.process_conf-433"><a href="#AndState.process_conf-433"><span class="linenos">433</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="AndState.process_conf-434"><a href="#AndState.process_conf-434"><span class="linenos">434</span></a>            <span class="p">],</span>
+</span><span id="AndState.process_conf-435"><a href="#AndState.process_conf-435"><span class="linenos">435</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="AndState.run" class="classattr">
+                                        <input id="AndState.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="AndState.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#AndState.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="AndState.run-455"><a href="#AndState.run-455"><span class="linenos">455</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndState.run-456"><a href="#AndState.run-456"><span class="linenos">456</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="AndState.run-457"><a href="#AndState.run-457"><span class="linenos">457</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="AndState.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="AndState.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="AndState.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="AndState.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="OrState">
+                            <input id="OrState-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">OrState</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="OrState-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#OrState"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="OrState-460"><a href="#OrState-460"><span class="linenos">460</span></a><span class="k">class</span><span class="w"> </span><span class="nc">OrState</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="OrState-461"><a href="#OrState-461"><span class="linenos">461</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Define disjunction of states.</span>
+</span><span id="OrState-462"><a href="#OrState-462"><span class="linenos">462</span></a>
+</span><span id="OrState-463"><a href="#OrState-463"><span class="linenos">463</span></a><span class="sd">    The &quot;states&quot; configuration key gets an array of states to be combined.</span>
+</span><span id="OrState-464"><a href="#OrState-464"><span class="linenos">464</span></a><span class="sd">    An OrState plugin client reacts to &quot;get state&quot; commands and sends</span>
+</span><span id="OrState-465"><a href="#OrState-465"><span class="linenos">465</span></a><span class="sd">    &quot;changed&quot; events when a change in one of the combined states leads to</span>
+</span><span id="OrState-466"><a href="#OrState-466"><span class="linenos">466</span></a><span class="sd">    a change for the disjunction:</span>
+</span><span id="OrState-467"><a href="#OrState-467"><span class="linenos">467</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="OrState-468"><a href="#OrState-468"><span class="linenos">468</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="OrState-469"><a href="#OrState-469"><span class="linenos">469</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="OrState-470"><a href="#OrState-470"><span class="linenos">470</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="OrState-471"><a href="#OrState-471"><span class="linenos">471</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="OrState-472"><a href="#OrState-472"><span class="linenos">472</span></a><span class="sd">    ...      &quot;Test OrState&quot;: {&quot;plugin&quot;: &quot;OrState&quot;,</span>
+</span><span id="OrState-473"><a href="#OrState-473"><span class="linenos">473</span></a><span class="sd">    ...                       &quot;states&quot;: [&quot;Test State 1&quot;, &quot;Test State 2&quot;]}},</span>
+</span><span id="OrState-474"><a href="#OrState-474"><span class="linenos">474</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="OrState-475"><a href="#OrState-475"><span class="linenos">475</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="OrState-476"><a href="#OrState-476"><span class="linenos">476</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="OrState-477"><a href="#OrState-477"><span class="linenos">477</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="OrState-478"><a href="#OrState-478"><span class="linenos">478</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="OrState-479"><a href="#OrState-479"><span class="linenos">479</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="OrState-480"><a href="#OrState-480"><span class="linenos">480</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrState&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="OrState-481"><a href="#OrState-481"><span class="linenos">481</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrState&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="OrState-482"><a href="#OrState-482"><span class="linenos">482</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="OrState-483"><a href="#OrState-483"><span class="linenos">483</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="OrState-484"><a href="#OrState-484"><span class="linenos">484</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="OrState-485"><a href="#OrState-485"><span class="linenos">485</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="OrState-486"><a href="#OrState-486"><span class="linenos">486</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="OrState-487"><a href="#OrState-487"><span class="linenos">487</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="OrState-488"><a href="#OrState-488"><span class="linenos">488</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrState-489"><a href="#OrState-489"><span class="linenos">489</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="OrState-490"><a href="#OrState-490"><span class="linenos">490</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="OrState-491"><a href="#OrState-491"><span class="linenos">491</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrState-492"><a href="#OrState-492"><span class="linenos">492</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrState-493"><a href="#OrState-493"><span class="linenos">493</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>
+</span><span id="OrState-494"><a href="#OrState-494"><span class="linenos">494</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="OrState-495"><a href="#OrState-495"><span class="linenos">495</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="OrState-496"><a href="#OrState-496"><span class="linenos">496</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>
+</span><span id="OrState-497"><a href="#OrState-497"><span class="linenos">497</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="OrState-498"><a href="#OrState-498"><span class="linenos">498</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrState-499"><a href="#OrState-499"><span class="linenos">499</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrState&#39;,</span>
+</span><span id="OrState-500"><a href="#OrState-500"><span class="linenos">500</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="OrState-501"><a href="#OrState-501"><span class="linenos">501</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="OrState-502"><a href="#OrState-502"><span class="linenos">502</span></a>
+</span><span id="OrState-503"><a href="#OrState-503"><span class="linenos">503</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="OrState-504"><a href="#OrState-504"><span class="linenos">504</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}},</span>
+</span><span id="OrState-505"><a href="#OrState-505"><span class="linenos">505</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">],</span>
+</span><span id="OrState-506"><a href="#OrState-506"><span class="linenos">506</span></a>    <span class="p">}</span>
+</span><span id="OrState-507"><a href="#OrState-507"><span class="linenos">507</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for OrState plugin configuration.</span>
+</span><span id="OrState-508"><a href="#OrState-508"><span class="linenos">508</span></a>
+</span><span id="OrState-509"><a href="#OrState-509"><span class="linenos">509</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="OrState-510"><a href="#OrState-510"><span class="linenos">510</span></a>
+</span><span id="OrState-511"><a href="#OrState-511"><span class="linenos">511</span></a><span class="sd">    - &#39;states&#39;: list of names of combined states.</span>
+</span><span id="OrState-512"><a href="#OrState-512"><span class="linenos">512</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="OrState-513"><a href="#OrState-513"><span class="linenos">513</span></a>
+</span><span id="OrState-514"><a href="#OrState-514"><span class="linenos">514</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState-515"><a href="#OrState-515"><span class="linenos">515</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="OrState-516"><a href="#OrState-516"><span class="linenos">516</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="OrState-517"><a href="#OrState-517"><span class="linenos">517</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="OrState-518"><a href="#OrState-518"><span class="linenos">518</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">]:</span>
+</span><span id="OrState-519"><a href="#OrState-519"><span class="linenos">519</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="OrState-520"><a href="#OrState-520"><span class="linenos">520</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState-521"><a href="#OrState-521"><span class="linenos">521</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="OrState-522"><a href="#OrState-522"><span class="linenos">522</span></a>                <span class="p">)</span>
+</span><span id="OrState-523"><a href="#OrState-523"><span class="linenos">523</span></a>            <span class="p">)</span>
+</span><span id="OrState-524"><a href="#OrState-524"><span class="linenos">524</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="OrState-525"><a href="#OrState-525"><span class="linenos">525</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="OrState-526"><a href="#OrState-526"><span class="linenos">526</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="OrState-527"><a href="#OrState-527"><span class="linenos">527</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="OrState-528"><a href="#OrState-528"><span class="linenos">528</span></a>            <span class="s2">&quot;OrState&quot;</span><span class="p">,</span>
+</span><span id="OrState-529"><a href="#OrState-529"><span class="linenos">529</span></a>            <span class="p">[</span>
+</span><span id="OrState-530"><a href="#OrState-530"><span class="linenos">530</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState-531"><a href="#OrState-531"><span class="linenos">531</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="OrState-532"><a href="#OrState-532"><span class="linenos">532</span></a>                <span class="p">),</span>
+</span><span id="OrState-533"><a href="#OrState-533"><span class="linenos">533</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="OrState-534"><a href="#OrState-534"><span class="linenos">534</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState-535"><a href="#OrState-535"><span class="linenos">535</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="OrState-536"><a href="#OrState-536"><span class="linenos">536</span></a>                <span class="p">),</span>
+</span><span id="OrState-537"><a href="#OrState-537"><span class="linenos">537</span></a>            <span class="p">],</span>
+</span><span id="OrState-538"><a href="#OrState-538"><span class="linenos">538</span></a>            <span class="p">[</span>
+</span><span id="OrState-539"><a href="#OrState-539"><span class="linenos">539</span></a>                <span class="p">(</span>
+</span><span id="OrState-540"><a href="#OrState-540"><span class="linenos">540</span></a>                    <span class="p">[</span>
+</span><span id="OrState-541"><a href="#OrState-541"><span class="linenos">541</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState-542"><a href="#OrState-542"><span class="linenos">542</span></a>                            <span class="p">{</span>
+</span><span id="OrState-543"><a href="#OrState-543"><span class="linenos">543</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrState-544"><a href="#OrState-544"><span class="linenos">544</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="OrState-545"><a href="#OrState-545"><span class="linenos">545</span></a>                            <span class="p">}</span>
+</span><span id="OrState-546"><a href="#OrState-546"><span class="linenos">546</span></a>                        <span class="p">)</span>
+</span><span id="OrState-547"><a href="#OrState-547"><span class="linenos">547</span></a>                    <span class="p">],</span>
+</span><span id="OrState-548"><a href="#OrState-548"><span class="linenos">548</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="OrState-549"><a href="#OrState-549"><span class="linenos">549</span></a>                <span class="p">),</span>
+</span><span id="OrState-550"><a href="#OrState-550"><span class="linenos">550</span></a>                <span class="p">(</span>
+</span><span id="OrState-551"><a href="#OrState-551"><span class="linenos">551</span></a>                    <span class="p">[</span>
+</span><span id="OrState-552"><a href="#OrState-552"><span class="linenos">552</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState-553"><a href="#OrState-553"><span class="linenos">553</span></a>                            <span class="p">{</span>
+</span><span id="OrState-554"><a href="#OrState-554"><span class="linenos">554</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrState-555"><a href="#OrState-555"><span class="linenos">555</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="OrState-556"><a href="#OrState-556"><span class="linenos">556</span></a>                            <span class="p">}</span>
+</span><span id="OrState-557"><a href="#OrState-557"><span class="linenos">557</span></a>                        <span class="p">)</span>
+</span><span id="OrState-558"><a href="#OrState-558"><span class="linenos">558</span></a>                    <span class="p">],</span>
+</span><span id="OrState-559"><a href="#OrState-559"><span class="linenos">559</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="OrState-560"><a href="#OrState-560"><span class="linenos">560</span></a>                <span class="p">),</span>
+</span><span id="OrState-561"><a href="#OrState-561"><span class="linenos">561</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="OrState-562"><a href="#OrState-562"><span class="linenos">562</span></a>            <span class="p">],</span>
+</span><span id="OrState-563"><a href="#OrState-563"><span class="linenos">563</span></a>        <span class="p">)</span>
+</span><span id="OrState-564"><a href="#OrState-564"><span class="linenos">564</span></a>
+</span><span id="OrState-565"><a href="#OrState-565"><span class="linenos">565</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState-566"><a href="#OrState-566"><span class="linenos">566</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">}))</span>
+</span><span id="OrState-567"><a href="#OrState-567"><span class="linenos">567</span></a>
+</span><span id="OrState-568"><a href="#OrState-568"><span class="linenos">568</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState-569"><a href="#OrState-569"><span class="linenos">569</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="OrState-570"><a href="#OrState-570"><span class="linenos">570</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="OrState-571"><a href="#OrState-571"><span class="linenos">571</span></a>
+</span><span id="OrState-572"><a href="#OrState-572"><span class="linenos">572</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState-573"><a href="#OrState-573"><span class="linenos">573</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="OrState-574"><a href="#OrState-574"><span class="linenos">574</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="OrState-575"><a href="#OrState-575"><span class="linenos">575</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="OrState-576"><a href="#OrState-576"><span class="linenos">576</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="OrState-577"><a href="#OrState-577"><span class="linenos">577</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="OrState-578"><a href="#OrState-578"><span class="linenos">578</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="OrState-579"><a href="#OrState-579"><span class="linenos">579</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="OrState-580"><a href="#OrState-580"><span class="linenos">580</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">,</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">})</span>
+</span><span id="OrState-581"><a href="#OrState-581"><span class="linenos">581</span></a>            <span class="p">)</span>
+</span><span id="OrState-582"><a href="#OrState-582"><span class="linenos">582</span></a>
+</span><span id="OrState-583"><a href="#OrState-583"><span class="linenos">583</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState-584"><a href="#OrState-584"><span class="linenos">584</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="OrState-585"><a href="#OrState-585"><span class="linenos">585</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Define disjunction of states.</p>
+
+<p>The "states" configuration key gets an array of states to be combined.
+An OrState plugin client reacts to "get state" commands and sends
+"changed" events when a change in one of the combined states leads to
+a change for the disjunction:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 2&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test OrState&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;OrState&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                      <span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test OrState&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test OrState&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get sources&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrState&#39;,</span>
+<span class="go">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="OrState.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;states&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}}, &#39;required&#39;: [&#39;states&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#OrState.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for OrState plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'states': list of names of combined states.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="OrState.process_conf" class="classattr">
+                                        <input id="OrState.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="OrState.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#OrState.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="OrState.process_conf-514"><a href="#OrState.process_conf-514"><span class="linenos">514</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState.process_conf-515"><a href="#OrState.process_conf-515"><span class="linenos">515</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="OrState.process_conf-516"><a href="#OrState.process_conf-516"><span class="linenos">516</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="OrState.process_conf-517"><a href="#OrState.process_conf-517"><span class="linenos">517</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="OrState.process_conf-518"><a href="#OrState.process_conf-518"><span class="linenos">518</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;states&quot;</span><span class="p">]:</span>
+</span><span id="OrState.process_conf-519"><a href="#OrState.process_conf-519"><span class="linenos">519</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="OrState.process_conf-520"><a href="#OrState.process_conf-520"><span class="linenos">520</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState.process_conf-521"><a href="#OrState.process_conf-521"><span class="linenos">521</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="OrState.process_conf-522"><a href="#OrState.process_conf-522"><span class="linenos">522</span></a>                <span class="p">)</span>
+</span><span id="OrState.process_conf-523"><a href="#OrState.process_conf-523"><span class="linenos">523</span></a>            <span class="p">)</span>
+</span><span id="OrState.process_conf-524"><a href="#OrState.process_conf-524"><span class="linenos">524</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="OrState.process_conf-525"><a href="#OrState.process_conf-525"><span class="linenos">525</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="OrState.process_conf-526"><a href="#OrState.process_conf-526"><span class="linenos">526</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="OrState.process_conf-527"><a href="#OrState.process_conf-527"><span class="linenos">527</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="OrState.process_conf-528"><a href="#OrState.process_conf-528"><span class="linenos">528</span></a>            <span class="s2">&quot;OrState&quot;</span><span class="p">,</span>
+</span><span id="OrState.process_conf-529"><a href="#OrState.process_conf-529"><span class="linenos">529</span></a>            <span class="p">[</span>
+</span><span id="OrState.process_conf-530"><a href="#OrState.process_conf-530"><span class="linenos">530</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState.process_conf-531"><a href="#OrState.process_conf-531"><span class="linenos">531</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;changed&quot;</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="OrState.process_conf-532"><a href="#OrState.process_conf-532"><span class="linenos">532</span></a>                <span class="p">),</span>
+</span><span id="OrState.process_conf-533"><a href="#OrState.process_conf-533"><span class="linenos">533</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}),</span>
+</span><span id="OrState.process_conf-534"><a href="#OrState.process_conf-534"><span class="linenos">534</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState.process_conf-535"><a href="#OrState.process_conf-535"><span class="linenos">535</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="OrState.process_conf-536"><a href="#OrState.process_conf-536"><span class="linenos">536</span></a>                <span class="p">),</span>
+</span><span id="OrState.process_conf-537"><a href="#OrState.process_conf-537"><span class="linenos">537</span></a>            <span class="p">],</span>
+</span><span id="OrState.process_conf-538"><a href="#OrState.process_conf-538"><span class="linenos">538</span></a>            <span class="p">[</span>
+</span><span id="OrState.process_conf-539"><a href="#OrState.process_conf-539"><span class="linenos">539</span></a>                <span class="p">(</span>
+</span><span id="OrState.process_conf-540"><a href="#OrState.process_conf-540"><span class="linenos">540</span></a>                    <span class="p">[</span>
+</span><span id="OrState.process_conf-541"><a href="#OrState.process_conf-541"><span class="linenos">541</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState.process_conf-542"><a href="#OrState.process_conf-542"><span class="linenos">542</span></a>                            <span class="p">{</span>
+</span><span id="OrState.process_conf-543"><a href="#OrState.process_conf-543"><span class="linenos">543</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrState.process_conf-544"><a href="#OrState.process_conf-544"><span class="linenos">544</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="OrState.process_conf-545"><a href="#OrState.process_conf-545"><span class="linenos">545</span></a>                            <span class="p">}</span>
+</span><span id="OrState.process_conf-546"><a href="#OrState.process_conf-546"><span class="linenos">546</span></a>                        <span class="p">)</span>
+</span><span id="OrState.process_conf-547"><a href="#OrState.process_conf-547"><span class="linenos">547</span></a>                    <span class="p">],</span>
+</span><span id="OrState.process_conf-548"><a href="#OrState.process_conf-548"><span class="linenos">548</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="OrState.process_conf-549"><a href="#OrState.process_conf-549"><span class="linenos">549</span></a>                <span class="p">),</span>
+</span><span id="OrState.process_conf-550"><a href="#OrState.process_conf-550"><span class="linenos">550</span></a>                <span class="p">(</span>
+</span><span id="OrState.process_conf-551"><a href="#OrState.process_conf-551"><span class="linenos">551</span></a>                    <span class="p">[</span>
+</span><span id="OrState.process_conf-552"><a href="#OrState.process_conf-552"><span class="linenos">552</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrState.process_conf-553"><a href="#OrState.process_conf-553"><span class="linenos">553</span></a>                            <span class="p">{</span>
+</span><span id="OrState.process_conf-554"><a href="#OrState.process_conf-554"><span class="linenos">554</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrState.process_conf-555"><a href="#OrState.process_conf-555"><span class="linenos">555</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="OrState.process_conf-556"><a href="#OrState.process_conf-556"><span class="linenos">556</span></a>                            <span class="p">}</span>
+</span><span id="OrState.process_conf-557"><a href="#OrState.process_conf-557"><span class="linenos">557</span></a>                        <span class="p">)</span>
+</span><span id="OrState.process_conf-558"><a href="#OrState.process_conf-558"><span class="linenos">558</span></a>                    <span class="p">],</span>
+</span><span id="OrState.process_conf-559"><a href="#OrState.process_conf-559"><span class="linenos">559</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="OrState.process_conf-560"><a href="#OrState.process_conf-560"><span class="linenos">560</span></a>                <span class="p">),</span>
+</span><span id="OrState.process_conf-561"><a href="#OrState.process_conf-561"><span class="linenos">561</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="OrState.process_conf-562"><a href="#OrState.process_conf-562"><span class="linenos">562</span></a>            <span class="p">],</span>
+</span><span id="OrState.process_conf-563"><a href="#OrState.process_conf-563"><span class="linenos">563</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="OrState.run" class="classattr">
+                                        <input id="OrState.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="OrState.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#OrState.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="OrState.run-583"><a href="#OrState.run-583"><span class="linenos">583</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrState.run-584"><a href="#OrState.run-584"><span class="linenos">584</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="OrState.run-585"><a href="#OrState.run-585"><span class="linenos">585</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="OrState.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="OrState.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="OrState.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="OrState.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="AndSet">
+                            <input id="AndSet-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">AndSet</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="AndSet-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#AndSet"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="AndSet-588"><a href="#AndSet-588"><span class="linenos">588</span></a><span class="k">class</span><span class="w"> </span><span class="nc">AndSet</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="AndSet-589"><a href="#AndSet-589"><span class="linenos">589</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Set state based on conjunction of other states.</span>
+</span><span id="AndSet-590"><a href="#AndSet-590"><span class="linenos">590</span></a>
+</span><span id="AndSet-591"><a href="#AndSet-591"><span class="linenos">591</span></a><span class="sd">    The &quot;input states&quot; configuration key gets an array of states used to</span>
+</span><span id="AndSet-592"><a href="#AndSet-592"><span class="linenos">592</span></a><span class="sd">    determine the state in the &quot;output state&quot; configuration key:</span>
+</span><span id="AndSet-593"><a href="#AndSet-593"><span class="linenos">593</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="AndSet-594"><a href="#AndSet-594"><span class="linenos">594</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="AndSet-595"><a href="#AndSet-595"><span class="linenos">595</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="AndSet-596"><a href="#AndSet-596"><span class="linenos">596</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="AndSet-597"><a href="#AndSet-597"><span class="linenos">597</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="AndSet-598"><a href="#AndSet-598"><span class="linenos">598</span></a><span class="sd">    ...      &quot;Test State 3&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="AndSet-599"><a href="#AndSet-599"><span class="linenos">599</span></a><span class="sd">    ...      &quot;Test AndSet&quot;: {&quot;plugin&quot;: &quot;AndSet&quot;,</span>
+</span><span id="AndSet-600"><a href="#AndSet-600"><span class="linenos">600</span></a><span class="sd">    ...                      &quot;input states&quot;: [&quot;Test State 1&quot;,</span>
+</span><span id="AndSet-601"><a href="#AndSet-601"><span class="linenos">601</span></a><span class="sd">    ...                                       &quot;Test State 2&quot;],</span>
+</span><span id="AndSet-602"><a href="#AndSet-602"><span class="linenos">602</span></a><span class="sd">    ...                      &quot;output state&quot;: &quot;Test State 3&quot;}},</span>
+</span><span id="AndSet-603"><a href="#AndSet-603"><span class="linenos">603</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="AndSet-604"><a href="#AndSet-604"><span class="linenos">604</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="AndSet-605"><a href="#AndSet-605"><span class="linenos">605</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="AndSet-606"><a href="#AndSet-606"><span class="linenos">606</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="AndSet-607"><a href="#AndSet-607"><span class="linenos">607</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndSet&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="AndSet-608"><a href="#AndSet-608"><span class="linenos">608</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="AndSet-609"><a href="#AndSet-609"><span class="linenos">609</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="AndSet-610"><a href="#AndSet-610"><span class="linenos">610</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndSet&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="AndSet-611"><a href="#AndSet-611"><span class="linenos">611</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test AndSet&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="AndSet-612"><a href="#AndSet-612"><span class="linenos">612</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="AndSet-613"><a href="#AndSet-613"><span class="linenos">613</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="AndSet-614"><a href="#AndSet-614"><span class="linenos">614</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="AndSet-615"><a href="#AndSet-615"><span class="linenos">615</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="AndSet-616"><a href="#AndSet-616"><span class="linenos">616</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="AndSet-617"><a href="#AndSet-617"><span class="linenos">617</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="AndSet-618"><a href="#AndSet-618"><span class="linenos">618</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndSet-619"><a href="#AndSet-619"><span class="linenos">619</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="AndSet-620"><a href="#AndSet-620"><span class="linenos">620</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="AndSet-621"><a href="#AndSet-621"><span class="linenos">621</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndSet-622"><a href="#AndSet-622"><span class="linenos">622</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="AndSet-623"><a href="#AndSet-623"><span class="linenos">623</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="AndSet-624"><a href="#AndSet-624"><span class="linenos">624</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="AndSet-625"><a href="#AndSet-625"><span class="linenos">625</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="AndSet-626"><a href="#AndSet-626"><span class="linenos">626</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="AndSet-627"><a href="#AndSet-627"><span class="linenos">627</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="AndSet-628"><a href="#AndSet-628"><span class="linenos">628</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="AndSet-629"><a href="#AndSet-629"><span class="linenos">629</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="AndSet-630"><a href="#AndSet-630"><span class="linenos">630</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="AndSet-631"><a href="#AndSet-631"><span class="linenos">631</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>
+</span><span id="AndSet-632"><a href="#AndSet-632"><span class="linenos">632</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndSet-633"><a href="#AndSet-633"><span class="linenos">633</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="AndSet-634"><a href="#AndSet-634"><span class="linenos">634</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="AndSet-635"><a href="#AndSet-635"><span class="linenos">635</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="AndSet-636"><a href="#AndSet-636"><span class="linenos">636</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="AndSet-637"><a href="#AndSet-637"><span class="linenos">637</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="AndSet-638"><a href="#AndSet-638"><span class="linenos">638</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="AndSet-639"><a href="#AndSet-639"><span class="linenos">639</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test AndSet&#39;,</span>
+</span><span id="AndSet-640"><a href="#AndSet-640"><span class="linenos">640</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="AndSet-641"><a href="#AndSet-641"><span class="linenos">641</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: True}</span>
+</span><span id="AndSet-642"><a href="#AndSet-642"><span class="linenos">642</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="AndSet-643"><a href="#AndSet-643"><span class="linenos">643</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="AndSet-644"><a href="#AndSet-644"><span class="linenos">644</span></a>
+</span><span id="AndSet-645"><a href="#AndSet-645"><span class="linenos">645</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="AndSet-646"><a href="#AndSet-646"><span class="linenos">646</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="AndSet-647"><a href="#AndSet-647"><span class="linenos">647</span></a>            <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}},</span>
+</span><span id="AndSet-648"><a href="#AndSet-648"><span class="linenos">648</span></a>            <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="AndSet-649"><a href="#AndSet-649"><span class="linenos">649</span></a>        <span class="p">},</span>
+</span><span id="AndSet-650"><a href="#AndSet-650"><span class="linenos">650</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">,</span> <span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="AndSet-651"><a href="#AndSet-651"><span class="linenos">651</span></a>    <span class="p">}</span>
+</span><span id="AndSet-652"><a href="#AndSet-652"><span class="linenos">652</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for AndSet plugin configuration.</span>
+</span><span id="AndSet-653"><a href="#AndSet-653"><span class="linenos">653</span></a>
+</span><span id="AndSet-654"><a href="#AndSet-654"><span class="linenos">654</span></a><span class="sd">    Required configuration keys:</span>
+</span><span id="AndSet-655"><a href="#AndSet-655"><span class="linenos">655</span></a>
+</span><span id="AndSet-656"><a href="#AndSet-656"><span class="linenos">656</span></a><span class="sd">    - &#39;input states&#39;: list of names of combined states.</span>
+</span><span id="AndSet-657"><a href="#AndSet-657"><span class="linenos">657</span></a><span class="sd">    - &#39;output state&#39;: name of state to be set.</span>
+</span><span id="AndSet-658"><a href="#AndSet-658"><span class="linenos">658</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="AndSet-659"><a href="#AndSet-659"><span class="linenos">659</span></a>
+</span><span id="AndSet-660"><a href="#AndSet-660"><span class="linenos">660</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet-661"><a href="#AndSet-661"><span class="linenos">661</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="AndSet-662"><a href="#AndSet-662"><span class="linenos">662</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="AndSet-663"><a href="#AndSet-663"><span class="linenos">663</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="AndSet-664"><a href="#AndSet-664"><span class="linenos">664</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">]:</span>
+</span><span id="AndSet-665"><a href="#AndSet-665"><span class="linenos">665</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="AndSet-666"><a href="#AndSet-666"><span class="linenos">666</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet-667"><a href="#AndSet-667"><span class="linenos">667</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="AndSet-668"><a href="#AndSet-668"><span class="linenos">668</span></a>                <span class="p">)</span>
+</span><span id="AndSet-669"><a href="#AndSet-669"><span class="linenos">669</span></a>            <span class="p">)</span>
+</span><span id="AndSet-670"><a href="#AndSet-670"><span class="linenos">670</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="AndSet-671"><a href="#AndSet-671"><span class="linenos">671</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="AndSet-672"><a href="#AndSet-672"><span class="linenos">672</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="AndSet-673"><a href="#AndSet-673"><span class="linenos">673</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="AndSet-674"><a href="#AndSet-674"><span class="linenos">674</span></a>            <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+</span><span id="AndSet-675"><a href="#AndSet-675"><span class="linenos">675</span></a>            <span class="p">[</span>
+</span><span id="AndSet-676"><a href="#AndSet-676"><span class="linenos">676</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet-677"><a href="#AndSet-677"><span class="linenos">677</span></a>                    <span class="p">{</span>
+</span><span id="AndSet-678"><a href="#AndSet-678"><span class="linenos">678</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">]},</span>
+</span><span id="AndSet-679"><a href="#AndSet-679"><span class="linenos">679</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="AndSet-680"><a href="#AndSet-680"><span class="linenos">680</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="AndSet-681"><a href="#AndSet-681"><span class="linenos">681</span></a>                    <span class="p">}</span>
+</span><span id="AndSet-682"><a href="#AndSet-682"><span class="linenos">682</span></a>                <span class="p">),</span>
+</span><span id="AndSet-683"><a href="#AndSet-683"><span class="linenos">683</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet-684"><a href="#AndSet-684"><span class="linenos">684</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="AndSet-685"><a href="#AndSet-685"><span class="linenos">685</span></a>                <span class="p">),</span>
+</span><span id="AndSet-686"><a href="#AndSet-686"><span class="linenos">686</span></a>            <span class="p">],</span>
+</span><span id="AndSet-687"><a href="#AndSet-687"><span class="linenos">687</span></a>            <span class="p">[</span>
+</span><span id="AndSet-688"><a href="#AndSet-688"><span class="linenos">688</span></a>                <span class="p">(</span>
+</span><span id="AndSet-689"><a href="#AndSet-689"><span class="linenos">689</span></a>                    <span class="p">[</span>
+</span><span id="AndSet-690"><a href="#AndSet-690"><span class="linenos">690</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet-691"><a href="#AndSet-691"><span class="linenos">691</span></a>                            <span class="p">{</span>
+</span><span id="AndSet-692"><a href="#AndSet-692"><span class="linenos">692</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndSet-693"><a href="#AndSet-693"><span class="linenos">693</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="AndSet-694"><a href="#AndSet-694"><span class="linenos">694</span></a>                            <span class="p">}</span>
+</span><span id="AndSet-695"><a href="#AndSet-695"><span class="linenos">695</span></a>                        <span class="p">)</span>
+</span><span id="AndSet-696"><a href="#AndSet-696"><span class="linenos">696</span></a>                    <span class="p">],</span>
+</span><span id="AndSet-697"><a href="#AndSet-697"><span class="linenos">697</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="AndSet-698"><a href="#AndSet-698"><span class="linenos">698</span></a>                <span class="p">),</span>
+</span><span id="AndSet-699"><a href="#AndSet-699"><span class="linenos">699</span></a>                <span class="p">(</span>
+</span><span id="AndSet-700"><a href="#AndSet-700"><span class="linenos">700</span></a>                    <span class="p">[</span>
+</span><span id="AndSet-701"><a href="#AndSet-701"><span class="linenos">701</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet-702"><a href="#AndSet-702"><span class="linenos">702</span></a>                            <span class="p">{</span>
+</span><span id="AndSet-703"><a href="#AndSet-703"><span class="linenos">703</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndSet-704"><a href="#AndSet-704"><span class="linenos">704</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="AndSet-705"><a href="#AndSet-705"><span class="linenos">705</span></a>                            <span class="p">}</span>
+</span><span id="AndSet-706"><a href="#AndSet-706"><span class="linenos">706</span></a>                        <span class="p">)</span>
+</span><span id="AndSet-707"><a href="#AndSet-707"><span class="linenos">707</span></a>                    <span class="p">],</span>
+</span><span id="AndSet-708"><a href="#AndSet-708"><span class="linenos">708</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="AndSet-709"><a href="#AndSet-709"><span class="linenos">709</span></a>                <span class="p">),</span>
+</span><span id="AndSet-710"><a href="#AndSet-710"><span class="linenos">710</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="AndSet-711"><a href="#AndSet-711"><span class="linenos">711</span></a>            <span class="p">],</span>
+</span><span id="AndSet-712"><a href="#AndSet-712"><span class="linenos">712</span></a>        <span class="p">)</span>
+</span><span id="AndSet-713"><a href="#AndSet-713"><span class="linenos">713</span></a>
+</span><span id="AndSet-714"><a href="#AndSet-714"><span class="linenos">714</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet-715"><a href="#AndSet-715"><span class="linenos">715</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="AndSet-716"><a href="#AndSet-716"><span class="linenos">716</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="AndSet-717"><a href="#AndSet-717"><span class="linenos">717</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="AndSet-718"><a href="#AndSet-718"><span class="linenos">718</span></a>                <span class="p">{</span>
+</span><span id="AndSet-719"><a href="#AndSet-719"><span class="linenos">719</span></a>                    <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="AndSet-720"><a href="#AndSet-720"><span class="linenos">720</span></a>                    <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="AndSet-721"><a href="#AndSet-721"><span class="linenos">721</span></a>                    <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="AndSet-722"><a href="#AndSet-722"><span class="linenos">722</span></a>                <span class="p">},</span>
+</span><span id="AndSet-723"><a href="#AndSet-723"><span class="linenos">723</span></a>            <span class="p">)</span>
+</span><span id="AndSet-724"><a href="#AndSet-724"><span class="linenos">724</span></a>        <span class="p">)</span>
+</span><span id="AndSet-725"><a href="#AndSet-725"><span class="linenos">725</span></a>
+</span><span id="AndSet-726"><a href="#AndSet-726"><span class="linenos">726</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet-727"><a href="#AndSet-727"><span class="linenos">727</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="AndSet-728"><a href="#AndSet-728"><span class="linenos">728</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="AndSet-729"><a href="#AndSet-729"><span class="linenos">729</span></a>
+</span><span id="AndSet-730"><a href="#AndSet-730"><span class="linenos">730</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet-731"><a href="#AndSet-731"><span class="linenos">731</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="AndSet-732"><a href="#AndSet-732"><span class="linenos">732</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="AndSet-733"><a href="#AndSet-733"><span class="linenos">733</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="AndSet-734"><a href="#AndSet-734"><span class="linenos">734</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="AndSet-735"><a href="#AndSet-735"><span class="linenos">735</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="AndSet-736"><a href="#AndSet-736"><span class="linenos">736</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="AndSet-737"><a href="#AndSet-737"><span class="linenos">737</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="AndSet-738"><a href="#AndSet-738"><span class="linenos">738</span></a>                <span class="n">Message</span><span class="p">(</span>
+</span><span id="AndSet-739"><a href="#AndSet-739"><span class="linenos">739</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="AndSet-740"><a href="#AndSet-740"><span class="linenos">740</span></a>                    <span class="p">{</span>
+</span><span id="AndSet-741"><a href="#AndSet-741"><span class="linenos">741</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="AndSet-742"><a href="#AndSet-742"><span class="linenos">742</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="AndSet-743"><a href="#AndSet-743"><span class="linenos">743</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="AndSet-744"><a href="#AndSet-744"><span class="linenos">744</span></a>                    <span class="p">},</span>
+</span><span id="AndSet-745"><a href="#AndSet-745"><span class="linenos">745</span></a>                <span class="p">)</span>
+</span><span id="AndSet-746"><a href="#AndSet-746"><span class="linenos">746</span></a>            <span class="p">)</span>
+</span><span id="AndSet-747"><a href="#AndSet-747"><span class="linenos">747</span></a>
+</span><span id="AndSet-748"><a href="#AndSet-748"><span class="linenos">748</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet-749"><a href="#AndSet-749"><span class="linenos">749</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="AndSet-750"><a href="#AndSet-750"><span class="linenos">750</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Set state based on conjunction of other states.</p>
+
+<p>The "input states" configuration key gets an array of states used to
+determine the state in the "output state" configuration key:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 2&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 3&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test AndSet&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                     <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                                      <span class="s2">&quot;Test State 2&quot;</span><span class="p">],</span>
+<span class="gp">... </span>                     <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 3&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test AndSet&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test AndSet&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test AndSet&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get sources&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;,</span>
+<span class="go">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="AndSet.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<input id="AndSet.CONF_SCHEMA-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="AndSet.CONF_SCHEMA-view-value"></label><span class="default_value">{&#39;properties&#39;: {&#39;input states&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;output state&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;required&#39;: [&#39;input states&#39;, &#39;output state&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#AndSet.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for AndSet plugin configuration.</p>
+
+<p>Required configuration keys:</p>
+
+<ul>
+<li>'input states': list of names of combined states.</li>
+<li>'output state': name of state to be set.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="AndSet.process_conf" class="classattr">
+                                        <input id="AndSet.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="AndSet.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#AndSet.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="AndSet.process_conf-660"><a href="#AndSet.process_conf-660"><span class="linenos">660</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet.process_conf-661"><a href="#AndSet.process_conf-661"><span class="linenos">661</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="AndSet.process_conf-662"><a href="#AndSet.process_conf-662"><span class="linenos">662</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="AndSet.process_conf-663"><a href="#AndSet.process_conf-663"><span class="linenos">663</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="AndSet.process_conf-664"><a href="#AndSet.process_conf-664"><span class="linenos">664</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">]:</span>
+</span><span id="AndSet.process_conf-665"><a href="#AndSet.process_conf-665"><span class="linenos">665</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-666"><a href="#AndSet.process_conf-666"><span class="linenos">666</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-667"><a href="#AndSet.process_conf-667"><span class="linenos">667</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="AndSet.process_conf-668"><a href="#AndSet.process_conf-668"><span class="linenos">668</span></a>                <span class="p">)</span>
+</span><span id="AndSet.process_conf-669"><a href="#AndSet.process_conf-669"><span class="linenos">669</span></a>            <span class="p">)</span>
+</span><span id="AndSet.process_conf-670"><a href="#AndSet.process_conf-670"><span class="linenos">670</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="AndSet.process_conf-671"><a href="#AndSet.process_conf-671"><span class="linenos">671</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">all</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="AndSet.process_conf-672"><a href="#AndSet.process_conf-672"><span class="linenos">672</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-673"><a href="#AndSet.process_conf-673"><span class="linenos">673</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="AndSet.process_conf-674"><a href="#AndSet.process_conf-674"><span class="linenos">674</span></a>            <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+</span><span id="AndSet.process_conf-675"><a href="#AndSet.process_conf-675"><span class="linenos">675</span></a>            <span class="p">[</span>
+</span><span id="AndSet.process_conf-676"><a href="#AndSet.process_conf-676"><span class="linenos">676</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-677"><a href="#AndSet.process_conf-677"><span class="linenos">677</span></a>                    <span class="p">{</span>
+</span><span id="AndSet.process_conf-678"><a href="#AndSet.process_conf-678"><span class="linenos">678</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">]},</span>
+</span><span id="AndSet.process_conf-679"><a href="#AndSet.process_conf-679"><span class="linenos">679</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="AndSet.process_conf-680"><a href="#AndSet.process_conf-680"><span class="linenos">680</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="AndSet.process_conf-681"><a href="#AndSet.process_conf-681"><span class="linenos">681</span></a>                    <span class="p">}</span>
+</span><span id="AndSet.process_conf-682"><a href="#AndSet.process_conf-682"><span class="linenos">682</span></a>                <span class="p">),</span>
+</span><span id="AndSet.process_conf-683"><a href="#AndSet.process_conf-683"><span class="linenos">683</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-684"><a href="#AndSet.process_conf-684"><span class="linenos">684</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="AndSet.process_conf-685"><a href="#AndSet.process_conf-685"><span class="linenos">685</span></a>                <span class="p">),</span>
+</span><span id="AndSet.process_conf-686"><a href="#AndSet.process_conf-686"><span class="linenos">686</span></a>            <span class="p">],</span>
+</span><span id="AndSet.process_conf-687"><a href="#AndSet.process_conf-687"><span class="linenos">687</span></a>            <span class="p">[</span>
+</span><span id="AndSet.process_conf-688"><a href="#AndSet.process_conf-688"><span class="linenos">688</span></a>                <span class="p">(</span>
+</span><span id="AndSet.process_conf-689"><a href="#AndSet.process_conf-689"><span class="linenos">689</span></a>                    <span class="p">[</span>
+</span><span id="AndSet.process_conf-690"><a href="#AndSet.process_conf-690"><span class="linenos">690</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-691"><a href="#AndSet.process_conf-691"><span class="linenos">691</span></a>                            <span class="p">{</span>
+</span><span id="AndSet.process_conf-692"><a href="#AndSet.process_conf-692"><span class="linenos">692</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndSet.process_conf-693"><a href="#AndSet.process_conf-693"><span class="linenos">693</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="AndSet.process_conf-694"><a href="#AndSet.process_conf-694"><span class="linenos">694</span></a>                            <span class="p">}</span>
+</span><span id="AndSet.process_conf-695"><a href="#AndSet.process_conf-695"><span class="linenos">695</span></a>                        <span class="p">)</span>
+</span><span id="AndSet.process_conf-696"><a href="#AndSet.process_conf-696"><span class="linenos">696</span></a>                    <span class="p">],</span>
+</span><span id="AndSet.process_conf-697"><a href="#AndSet.process_conf-697"><span class="linenos">697</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="AndSet.process_conf-698"><a href="#AndSet.process_conf-698"><span class="linenos">698</span></a>                <span class="p">),</span>
+</span><span id="AndSet.process_conf-699"><a href="#AndSet.process_conf-699"><span class="linenos">699</span></a>                <span class="p">(</span>
+</span><span id="AndSet.process_conf-700"><a href="#AndSet.process_conf-700"><span class="linenos">700</span></a>                    <span class="p">[</span>
+</span><span id="AndSet.process_conf-701"><a href="#AndSet.process_conf-701"><span class="linenos">701</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="AndSet.process_conf-702"><a href="#AndSet.process_conf-702"><span class="linenos">702</span></a>                            <span class="p">{</span>
+</span><span id="AndSet.process_conf-703"><a href="#AndSet.process_conf-703"><span class="linenos">703</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="AndSet.process_conf-704"><a href="#AndSet.process_conf-704"><span class="linenos">704</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="AndSet.process_conf-705"><a href="#AndSet.process_conf-705"><span class="linenos">705</span></a>                            <span class="p">}</span>
+</span><span id="AndSet.process_conf-706"><a href="#AndSet.process_conf-706"><span class="linenos">706</span></a>                        <span class="p">)</span>
+</span><span id="AndSet.process_conf-707"><a href="#AndSet.process_conf-707"><span class="linenos">707</span></a>                    <span class="p">],</span>
+</span><span id="AndSet.process_conf-708"><a href="#AndSet.process_conf-708"><span class="linenos">708</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="AndSet.process_conf-709"><a href="#AndSet.process_conf-709"><span class="linenos">709</span></a>                <span class="p">),</span>
+</span><span id="AndSet.process_conf-710"><a href="#AndSet.process_conf-710"><span class="linenos">710</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="AndSet.process_conf-711"><a href="#AndSet.process_conf-711"><span class="linenos">711</span></a>            <span class="p">],</span>
+</span><span id="AndSet.process_conf-712"><a href="#AndSet.process_conf-712"><span class="linenos">712</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="AndSet.run" class="classattr">
+                                        <input id="AndSet.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="AndSet.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#AndSet.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="AndSet.run-748"><a href="#AndSet.run-748"><span class="linenos">748</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="AndSet.run-749"><a href="#AndSet.run-749"><span class="linenos">749</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="AndSet.run-750"><a href="#AndSet.run-750"><span class="linenos">750</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="AndSet.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="AndSet.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="AndSet.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="AndSet.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="OrSet">
+                            <input id="OrSet-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">OrSet</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="OrSet-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#OrSet"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="OrSet-753"><a href="#OrSet-753"><span class="linenos">753</span></a><span class="k">class</span><span class="w"> </span><span class="nc">OrSet</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="OrSet-754"><a href="#OrSet-754"><span class="linenos">754</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Set state based on disjunction of other states.</span>
+</span><span id="OrSet-755"><a href="#OrSet-755"><span class="linenos">755</span></a>
+</span><span id="OrSet-756"><a href="#OrSet-756"><span class="linenos">756</span></a><span class="sd">    The &quot;input states&quot; configuration key gets an array of states used to</span>
+</span><span id="OrSet-757"><a href="#OrSet-757"><span class="linenos">757</span></a><span class="sd">    determine the state in the &quot;output state&quot; configuration key:</span>
+</span><span id="OrSet-758"><a href="#OrSet-758"><span class="linenos">758</span></a><span class="sd">    &gt;&gt;&gt; import asyncio</span>
+</span><span id="OrSet-759"><a href="#OrSet-759"><span class="linenos">759</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="OrSet-760"><a href="#OrSet-760"><span class="linenos">760</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="OrSet-761"><a href="#OrSet-761"><span class="linenos">761</span></a><span class="sd">    ...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="OrSet-762"><a href="#OrSet-762"><span class="linenos">762</span></a><span class="sd">    ...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="OrSet-763"><a href="#OrSet-763"><span class="linenos">763</span></a><span class="sd">    ...      &quot;Test State 3&quot;: {&quot;plugin&quot;: &quot;State&quot;},</span>
+</span><span id="OrSet-764"><a href="#OrSet-764"><span class="linenos">764</span></a><span class="sd">    ...      &quot;Test OrSet&quot;: {&quot;plugin&quot;: &quot;OrSet&quot;,</span>
+</span><span id="OrSet-765"><a href="#OrSet-765"><span class="linenos">765</span></a><span class="sd">    ...                      &quot;input states&quot;: [&quot;Test State 1&quot;,</span>
+</span><span id="OrSet-766"><a href="#OrSet-766"><span class="linenos">766</span></a><span class="sd">    ...                                       &quot;Test State 2&quot;],</span>
+</span><span id="OrSet-767"><a href="#OrSet-767"><span class="linenos">767</span></a><span class="sd">    ...                      &quot;output state&quot;: &quot;Test State 3&quot;}},</span>
+</span><span id="OrSet-768"><a href="#OrSet-768"><span class="linenos">768</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="OrSet-769"><a href="#OrSet-769"><span class="linenos">769</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="OrSet-770"><a href="#OrSet-770"><span class="linenos">770</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrSet&quot;, &quot;command&quot;: &quot;get state&quot;},</span>
+</span><span id="OrSet-771"><a href="#OrSet-771"><span class="linenos">771</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="OrSet-772"><a href="#OrSet-772"><span class="linenos">772</span></a><span class="sd">    ...       &quot;new state&quot;: True},</span>
+</span><span id="OrSet-773"><a href="#OrSet-773"><span class="linenos">773</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,</span>
+</span><span id="OrSet-774"><a href="#OrSet-774"><span class="linenos">774</span></a><span class="sd">    ...       &quot;new state&quot;: False},</span>
+</span><span id="OrSet-775"><a href="#OrSet-775"><span class="linenos">775</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test OrSet&quot;, &quot;command&quot;: &quot;get sources&quot;}]))</span>
+</span><span id="OrSet-776"><a href="#OrSet-776"><span class="linenos">776</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="OrSet-777"><a href="#OrSet-777"><span class="linenos">777</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+</span><span id="OrSet-778"><a href="#OrSet-778"><span class="linenos">778</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="OrSet-779"><a href="#OrSet-779"><span class="linenos">779</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="OrSet-780"><a href="#OrSet-780"><span class="linenos">780</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>
+</span><span id="OrSet-781"><a href="#OrSet-781"><span class="linenos">781</span></a><span class="sd">             &#39;command&#39;: &#39;get state&#39;}</span>
+</span><span id="OrSet-782"><a href="#OrSet-782"><span class="linenos">782</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrSet-783"><a href="#OrSet-783"><span class="linenos">783</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+</span><span id="OrSet-784"><a href="#OrSet-784"><span class="linenos">784</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="OrSet-785"><a href="#OrSet-785"><span class="linenos">785</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="OrSet-786"><a href="#OrSet-786"><span class="linenos">786</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="OrSet-787"><a href="#OrSet-787"><span class="linenos">787</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+</span><span id="OrSet-788"><a href="#OrSet-788"><span class="linenos">788</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+</span><span id="OrSet-789"><a href="#OrSet-789"><span class="linenos">789</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+</span><span id="OrSet-790"><a href="#OrSet-790"><span class="linenos">790</span></a><span class="sd">             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+</span><span id="OrSet-791"><a href="#OrSet-791"><span class="linenos">791</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrSet-792"><a href="#OrSet-792"><span class="linenos">792</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>
+</span><span id="OrSet-793"><a href="#OrSet-793"><span class="linenos">793</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+</span><span id="OrSet-794"><a href="#OrSet-794"><span class="linenos">794</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>
+</span><span id="OrSet-795"><a href="#OrSet-795"><span class="linenos">795</span></a><span class="sd">             &#39;command&#39;: &#39;get sources&#39;}</span>
+</span><span id="OrSet-796"><a href="#OrSet-796"><span class="linenos">796</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+</span><span id="OrSet-797"><a href="#OrSet-797"><span class="linenos">797</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test OrSet&#39;,</span>
+</span><span id="OrSet-798"><a href="#OrSet-798"><span class="linenos">798</span></a><span class="sd">             &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</span><span id="OrSet-799"><a href="#OrSet-799"><span class="linenos">799</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="OrSet-800"><a href="#OrSet-800"><span class="linenos">800</span></a>
+</span><span id="OrSet-801"><a href="#OrSet-801"><span class="linenos">801</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="OrSet-802"><a href="#OrSet-802"><span class="linenos">802</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="OrSet-803"><a href="#OrSet-803"><span class="linenos">803</span></a>            <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}},</span>
+</span><span id="OrSet-804"><a href="#OrSet-804"><span class="linenos">804</span></a>            <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="OrSet-805"><a href="#OrSet-805"><span class="linenos">805</span></a>        <span class="p">},</span>
+</span><span id="OrSet-806"><a href="#OrSet-806"><span class="linenos">806</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">,</span> <span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="OrSet-807"><a href="#OrSet-807"><span class="linenos">807</span></a>    <span class="p">}</span>
+</span><span id="OrSet-808"><a href="#OrSet-808"><span class="linenos">808</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for OrSet plugin configuration.</span>
+</span><span id="OrSet-809"><a href="#OrSet-809"><span class="linenos">809</span></a>
+</span><span id="OrSet-810"><a href="#OrSet-810"><span class="linenos">810</span></a><span class="sd">    Required configuration keys:</span>
+</span><span id="OrSet-811"><a href="#OrSet-811"><span class="linenos">811</span></a>
+</span><span id="OrSet-812"><a href="#OrSet-812"><span class="linenos">812</span></a><span class="sd">    - &#39;input states&#39;: list of names of combined states.</span>
+</span><span id="OrSet-813"><a href="#OrSet-813"><span class="linenos">813</span></a><span class="sd">    - &#39;output state&#39;: name of state to be set.</span>
+</span><span id="OrSet-814"><a href="#OrSet-814"><span class="linenos">814</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="OrSet-815"><a href="#OrSet-815"><span class="linenos">815</span></a>
+</span><span id="OrSet-816"><a href="#OrSet-816"><span class="linenos">816</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet-817"><a href="#OrSet-817"><span class="linenos">817</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="OrSet-818"><a href="#OrSet-818"><span class="linenos">818</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="OrSet-819"><a href="#OrSet-819"><span class="linenos">819</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="OrSet-820"><a href="#OrSet-820"><span class="linenos">820</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">]:</span>
+</span><span id="OrSet-821"><a href="#OrSet-821"><span class="linenos">821</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="OrSet-822"><a href="#OrSet-822"><span class="linenos">822</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet-823"><a href="#OrSet-823"><span class="linenos">823</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="OrSet-824"><a href="#OrSet-824"><span class="linenos">824</span></a>                <span class="p">)</span>
+</span><span id="OrSet-825"><a href="#OrSet-825"><span class="linenos">825</span></a>            <span class="p">)</span>
+</span><span id="OrSet-826"><a href="#OrSet-826"><span class="linenos">826</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="OrSet-827"><a href="#OrSet-827"><span class="linenos">827</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="OrSet-828"><a href="#OrSet-828"><span class="linenos">828</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="OrSet-829"><a href="#OrSet-829"><span class="linenos">829</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="OrSet-830"><a href="#OrSet-830"><span class="linenos">830</span></a>            <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+</span><span id="OrSet-831"><a href="#OrSet-831"><span class="linenos">831</span></a>            <span class="p">[</span>
+</span><span id="OrSet-832"><a href="#OrSet-832"><span class="linenos">832</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet-833"><a href="#OrSet-833"><span class="linenos">833</span></a>                    <span class="p">{</span>
+</span><span id="OrSet-834"><a href="#OrSet-834"><span class="linenos">834</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">]},</span>
+</span><span id="OrSet-835"><a href="#OrSet-835"><span class="linenos">835</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="OrSet-836"><a href="#OrSet-836"><span class="linenos">836</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="OrSet-837"><a href="#OrSet-837"><span class="linenos">837</span></a>                    <span class="p">}</span>
+</span><span id="OrSet-838"><a href="#OrSet-838"><span class="linenos">838</span></a>                <span class="p">),</span>
+</span><span id="OrSet-839"><a href="#OrSet-839"><span class="linenos">839</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet-840"><a href="#OrSet-840"><span class="linenos">840</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="OrSet-841"><a href="#OrSet-841"><span class="linenos">841</span></a>                <span class="p">),</span>
+</span><span id="OrSet-842"><a href="#OrSet-842"><span class="linenos">842</span></a>            <span class="p">],</span>
+</span><span id="OrSet-843"><a href="#OrSet-843"><span class="linenos">843</span></a>            <span class="p">[</span>
+</span><span id="OrSet-844"><a href="#OrSet-844"><span class="linenos">844</span></a>                <span class="p">(</span>
+</span><span id="OrSet-845"><a href="#OrSet-845"><span class="linenos">845</span></a>                    <span class="p">[</span>
+</span><span id="OrSet-846"><a href="#OrSet-846"><span class="linenos">846</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet-847"><a href="#OrSet-847"><span class="linenos">847</span></a>                            <span class="p">{</span>
+</span><span id="OrSet-848"><a href="#OrSet-848"><span class="linenos">848</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrSet-849"><a href="#OrSet-849"><span class="linenos">849</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="OrSet-850"><a href="#OrSet-850"><span class="linenos">850</span></a>                            <span class="p">}</span>
+</span><span id="OrSet-851"><a href="#OrSet-851"><span class="linenos">851</span></a>                        <span class="p">)</span>
+</span><span id="OrSet-852"><a href="#OrSet-852"><span class="linenos">852</span></a>                    <span class="p">],</span>
+</span><span id="OrSet-853"><a href="#OrSet-853"><span class="linenos">853</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="OrSet-854"><a href="#OrSet-854"><span class="linenos">854</span></a>                <span class="p">),</span>
+</span><span id="OrSet-855"><a href="#OrSet-855"><span class="linenos">855</span></a>                <span class="p">(</span>
+</span><span id="OrSet-856"><a href="#OrSet-856"><span class="linenos">856</span></a>                    <span class="p">[</span>
+</span><span id="OrSet-857"><a href="#OrSet-857"><span class="linenos">857</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet-858"><a href="#OrSet-858"><span class="linenos">858</span></a>                            <span class="p">{</span>
+</span><span id="OrSet-859"><a href="#OrSet-859"><span class="linenos">859</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrSet-860"><a href="#OrSet-860"><span class="linenos">860</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="OrSet-861"><a href="#OrSet-861"><span class="linenos">861</span></a>                            <span class="p">}</span>
+</span><span id="OrSet-862"><a href="#OrSet-862"><span class="linenos">862</span></a>                        <span class="p">)</span>
+</span><span id="OrSet-863"><a href="#OrSet-863"><span class="linenos">863</span></a>                    <span class="p">],</span>
+</span><span id="OrSet-864"><a href="#OrSet-864"><span class="linenos">864</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="OrSet-865"><a href="#OrSet-865"><span class="linenos">865</span></a>                <span class="p">),</span>
+</span><span id="OrSet-866"><a href="#OrSet-866"><span class="linenos">866</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="OrSet-867"><a href="#OrSet-867"><span class="linenos">867</span></a>            <span class="p">],</span>
+</span><span id="OrSet-868"><a href="#OrSet-868"><span class="linenos">868</span></a>        <span class="p">)</span>
+</span><span id="OrSet-869"><a href="#OrSet-869"><span class="linenos">869</span></a>
+</span><span id="OrSet-870"><a href="#OrSet-870"><span class="linenos">870</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet-871"><a href="#OrSet-871"><span class="linenos">871</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="OrSet-872"><a href="#OrSet-872"><span class="linenos">872</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="OrSet-873"><a href="#OrSet-873"><span class="linenos">873</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="OrSet-874"><a href="#OrSet-874"><span class="linenos">874</span></a>                <span class="p">{</span>
+</span><span id="OrSet-875"><a href="#OrSet-875"><span class="linenos">875</span></a>                    <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="OrSet-876"><a href="#OrSet-876"><span class="linenos">876</span></a>                    <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="OrSet-877"><a href="#OrSet-877"><span class="linenos">877</span></a>                    <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="OrSet-878"><a href="#OrSet-878"><span class="linenos">878</span></a>                <span class="p">},</span>
+</span><span id="OrSet-879"><a href="#OrSet-879"><span class="linenos">879</span></a>            <span class="p">)</span>
+</span><span id="OrSet-880"><a href="#OrSet-880"><span class="linenos">880</span></a>        <span class="p">)</span>
+</span><span id="OrSet-881"><a href="#OrSet-881"><span class="linenos">881</span></a>
+</span><span id="OrSet-882"><a href="#OrSet-882"><span class="linenos">882</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_sources</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet-883"><a href="#OrSet-883"><span class="linenos">883</span></a>        <span class="n">source_states</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
+</span><span id="OrSet-884"><a href="#OrSet-884"><span class="linenos">884</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="n">source_states</span><span class="p">}))</span>
+</span><span id="OrSet-885"><a href="#OrSet-885"><span class="linenos">885</span></a>
+</span><span id="OrSet-886"><a href="#OrSet-886"><span class="linenos">886</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet-887"><a href="#OrSet-887"><span class="linenos">887</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">],</span> <span class="nb">str</span><span class="p">)</span>
+</span><span id="OrSet-888"><a href="#OrSet-888"><span class="linenos">888</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">],</span> <span class="nb">bool</span><span class="p">)</span>
+</span><span id="OrSet-889"><a href="#OrSet-889"><span class="linenos">889</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
+</span><span id="OrSet-890"><a href="#OrSet-890"><span class="linenos">890</span></a>        <span class="n">new_state</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="OrSet-891"><a href="#OrSet-891"><span class="linenos">891</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">!=</span> <span class="n">new_state</span><span class="p">:</span>
+</span><span id="OrSet-892"><a href="#OrSet-892"><span class="linenos">892</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_state</span>
+</span><span id="OrSet-893"><a href="#OrSet-893"><span class="linenos">893</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="OrSet-894"><a href="#OrSet-894"><span class="linenos">894</span></a>                <span class="n">Message</span><span class="p">(</span>
+</span><span id="OrSet-895"><a href="#OrSet-895"><span class="linenos">895</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="OrSet-896"><a href="#OrSet-896"><span class="linenos">896</span></a>                    <span class="p">{</span>
+</span><span id="OrSet-897"><a href="#OrSet-897"><span class="linenos">897</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">],</span>
+</span><span id="OrSet-898"><a href="#OrSet-898"><span class="linenos">898</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+</span><span id="OrSet-899"><a href="#OrSet-899"><span class="linenos">899</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span>
+</span><span id="OrSet-900"><a href="#OrSet-900"><span class="linenos">900</span></a>                    <span class="p">},</span>
+</span><span id="OrSet-901"><a href="#OrSet-901"><span class="linenos">901</span></a>                <span class="p">)</span>
+</span><span id="OrSet-902"><a href="#OrSet-902"><span class="linenos">902</span></a>            <span class="p">)</span>
+</span><span id="OrSet-903"><a href="#OrSet-903"><span class="linenos">903</span></a>
+</span><span id="OrSet-904"><a href="#OrSet-904"><span class="linenos">904</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet-905"><a href="#OrSet-905"><span class="linenos">905</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="OrSet-906"><a href="#OrSet-906"><span class="linenos">906</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Set state based on disjunction of other states.</p>
+
+<p>The "input states" configuration key gets an array of states used to
+determine the state in the "output state" configuration key:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 2&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test State 3&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;State&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test OrSet&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;OrSet&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                     <span class="s2">&quot;input states&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                                      <span class="s2">&quot;Test State 2&quot;</span><span class="p">],</span>
+<span class="gp">... </span>                     <span class="s2">&quot;output state&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 3&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test OrSet&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 2&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test State 1&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test OrSet&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get state&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get sources&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;,</span>
+<span class="go">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="OrSet.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<input id="OrSet.CONF_SCHEMA-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="OrSet.CONF_SCHEMA-view-value"></label><span class="default_value">{&#39;properties&#39;: {&#39;input states&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;output state&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;required&#39;: [&#39;input states&#39;, &#39;output state&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#OrSet.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for OrSet plugin configuration.</p>
+
+<p>Required configuration keys:</p>
+
+<ul>
+<li>'input states': list of names of combined states.</li>
+<li>'output state': name of state to be set.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="OrSet.process_conf" class="classattr">
+                                        <input id="OrSet.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="OrSet.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#OrSet.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="OrSet.process_conf-816"><a href="#OrSet.process_conf-816"><span class="linenos">816</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet.process_conf-817"><a href="#OrSet.process_conf-817"><span class="linenos">817</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="OrSet.process_conf-818"><a href="#OrSet.process_conf-818"><span class="linenos">818</span></a>        <span class="n">updates</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">MessageTemplate</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="OrSet.process_conf-819"><a href="#OrSet.process_conf-819"><span class="linenos">819</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="OrSet.process_conf-820"><a href="#OrSet.process_conf-820"><span class="linenos">820</span></a>        <span class="k">for</span> <span class="n">state</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;input states&quot;</span><span class="p">]:</span>
+</span><span id="OrSet.process_conf-821"><a href="#OrSet.process_conf-821"><span class="linenos">821</span></a>            <span class="n">updates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-822"><a href="#OrSet.process_conf-822"><span class="linenos">822</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-823"><a href="#OrSet.process_conf-823"><span class="linenos">823</span></a>                    <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="n">state</span><span class="p">},</span> <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">}}</span>
+</span><span id="OrSet.process_conf-824"><a href="#OrSet.process_conf-824"><span class="linenos">824</span></a>                <span class="p">)</span>
+</span><span id="OrSet.process_conf-825"><a href="#OrSet.process_conf-825"><span class="linenos">825</span></a>            <span class="p">)</span>
+</span><span id="OrSet.process_conf-826"><a href="#OrSet.process_conf-826"><span class="linenos">826</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+</span><span id="OrSet.process_conf-827"><a href="#OrSet.process_conf-827"><span class="linenos">827</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">any</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
+</span><span id="OrSet.process_conf-828"><a href="#OrSet.process_conf-828"><span class="linenos">828</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-829"><a href="#OrSet.process_conf-829"><span class="linenos">829</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="OrSet.process_conf-830"><a href="#OrSet.process_conf-830"><span class="linenos">830</span></a>            <span class="s2">&quot;AndSet&quot;</span><span class="p">,</span>
+</span><span id="OrSet.process_conf-831"><a href="#OrSet.process_conf-831"><span class="linenos">831</span></a>            <span class="p">[</span>
+</span><span id="OrSet.process_conf-832"><a href="#OrSet.process_conf-832"><span class="linenos">832</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-833"><a href="#OrSet.process_conf-833"><span class="linenos">833</span></a>                    <span class="p">{</span>
+</span><span id="OrSet.process_conf-834"><a href="#OrSet.process_conf-834"><span class="linenos">834</span></a>                        <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;output state&quot;</span><span class="p">]},</span>
+</span><span id="OrSet.process_conf-835"><a href="#OrSet.process_conf-835"><span class="linenos">835</span></a>                        <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set state&quot;</span><span class="p">},</span>
+</span><span id="OrSet.process_conf-836"><a href="#OrSet.process_conf-836"><span class="linenos">836</span></a>                        <span class="s2">&quot;new state&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;boolean&quot;</span><span class="p">},</span>
+</span><span id="OrSet.process_conf-837"><a href="#OrSet.process_conf-837"><span class="linenos">837</span></a>                    <span class="p">}</span>
+</span><span id="OrSet.process_conf-838"><a href="#OrSet.process_conf-838"><span class="linenos">838</span></a>                <span class="p">),</span>
+</span><span id="OrSet.process_conf-839"><a href="#OrSet.process_conf-839"><span class="linenos">839</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-840"><a href="#OrSet.process_conf-840"><span class="linenos">840</span></a>                    <span class="p">{</span><span class="s2">&quot;states&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}}</span>
+</span><span id="OrSet.process_conf-841"><a href="#OrSet.process_conf-841"><span class="linenos">841</span></a>                <span class="p">),</span>
+</span><span id="OrSet.process_conf-842"><a href="#OrSet.process_conf-842"><span class="linenos">842</span></a>            <span class="p">],</span>
+</span><span id="OrSet.process_conf-843"><a href="#OrSet.process_conf-843"><span class="linenos">843</span></a>            <span class="p">[</span>
+</span><span id="OrSet.process_conf-844"><a href="#OrSet.process_conf-844"><span class="linenos">844</span></a>                <span class="p">(</span>
+</span><span id="OrSet.process_conf-845"><a href="#OrSet.process_conf-845"><span class="linenos">845</span></a>                    <span class="p">[</span>
+</span><span id="OrSet.process_conf-846"><a href="#OrSet.process_conf-846"><span class="linenos">846</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-847"><a href="#OrSet.process_conf-847"><span class="linenos">847</span></a>                            <span class="p">{</span>
+</span><span id="OrSet.process_conf-848"><a href="#OrSet.process_conf-848"><span class="linenos">848</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrSet.process_conf-849"><a href="#OrSet.process_conf-849"><span class="linenos">849</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get state&quot;</span><span class="p">},</span>
+</span><span id="OrSet.process_conf-850"><a href="#OrSet.process_conf-850"><span class="linenos">850</span></a>                            <span class="p">}</span>
+</span><span id="OrSet.process_conf-851"><a href="#OrSet.process_conf-851"><span class="linenos">851</span></a>                        <span class="p">)</span>
+</span><span id="OrSet.process_conf-852"><a href="#OrSet.process_conf-852"><span class="linenos">852</span></a>                    <span class="p">],</span>
+</span><span id="OrSet.process_conf-853"><a href="#OrSet.process_conf-853"><span class="linenos">853</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_state</span><span class="p">,</span>
+</span><span id="OrSet.process_conf-854"><a href="#OrSet.process_conf-854"><span class="linenos">854</span></a>                <span class="p">),</span>
+</span><span id="OrSet.process_conf-855"><a href="#OrSet.process_conf-855"><span class="linenos">855</span></a>                <span class="p">(</span>
+</span><span id="OrSet.process_conf-856"><a href="#OrSet.process_conf-856"><span class="linenos">856</span></a>                    <span class="p">[</span>
+</span><span id="OrSet.process_conf-857"><a href="#OrSet.process_conf-857"><span class="linenos">857</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="OrSet.process_conf-858"><a href="#OrSet.process_conf-858"><span class="linenos">858</span></a>                            <span class="p">{</span>
+</span><span id="OrSet.process_conf-859"><a href="#OrSet.process_conf-859"><span class="linenos">859</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="OrSet.process_conf-860"><a href="#OrSet.process_conf-860"><span class="linenos">860</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get sources&quot;</span><span class="p">},</span>
+</span><span id="OrSet.process_conf-861"><a href="#OrSet.process_conf-861"><span class="linenos">861</span></a>                            <span class="p">}</span>
+</span><span id="OrSet.process_conf-862"><a href="#OrSet.process_conf-862"><span class="linenos">862</span></a>                        <span class="p">)</span>
+</span><span id="OrSet.process_conf-863"><a href="#OrSet.process_conf-863"><span class="linenos">863</span></a>                    <span class="p">],</span>
+</span><span id="OrSet.process_conf-864"><a href="#OrSet.process_conf-864"><span class="linenos">864</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_sources</span><span class="p">,</span>
+</span><span id="OrSet.process_conf-865"><a href="#OrSet.process_conf-865"><span class="linenos">865</span></a>                <span class="p">),</span>
+</span><span id="OrSet.process_conf-866"><a href="#OrSet.process_conf-866"><span class="linenos">866</span></a>                <span class="p">(</span><span class="n">updates</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_update</span><span class="p">),</span>
+</span><span id="OrSet.process_conf-867"><a href="#OrSet.process_conf-867"><span class="linenos">867</span></a>            <span class="p">],</span>
+</span><span id="OrSet.process_conf-868"><a href="#OrSet.process_conf-868"><span class="linenos">868</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="OrSet.run" class="classattr">
+                                        <input id="OrSet.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="OrSet.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#OrSet.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="OrSet.run-904"><a href="#OrSet.run-904"><span class="linenos">904</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="OrSet.run-905"><a href="#OrSet.run-905"><span class="linenos">905</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="OrSet.run-906"><a href="#OrSet.run-906"><span class="linenos">906</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="OrSet.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="OrSet.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="OrSet.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="OrSet.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "../search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `../${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi_plugins/util.html b/doc/api/controlpi_plugins/util.html
new file mode 100644 (file)
index 0000000..a2800c1
--- /dev/null
@@ -0,0 +1,2680 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi_plugins.util API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="../controlpi_plugins.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;controlpi_plugins</a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="class" href="#Log">Log</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Log.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Log.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Log.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Init">Init</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Init.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Init.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Init.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Execute">Execute</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Execute.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Execute.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Execute.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Alias">Alias</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Alias.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Alias.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Alias.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Counter">Counter</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Counter.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Counter.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Counter.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Date">Date</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Date.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Date.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Date.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+<a href="./../controlpi_plugins.html">controlpi_plugins</a><wbr>.util    </h1>
+
+                        <div class="docstring"><p>Provide utility plugins for all kinds of systems.</p>
+
+<ul>
+<li>Log logs messages on stdout.</li>
+<li>Init sends list of messages on startup and on demand.</li>
+<li>Execute sends configurable list of messages on demand.</li>
+<li>Alias translates messages to an alias.</li>
+</ul>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Log&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                  <span class="s2">&quot;filter&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Alias&quot;</span><span class="p">}}]},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test Init&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">}]},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test Alias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;sender&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Init&quot;</span><span class="p">},</span>
+<span class="gp">... </span>                             <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span>
+<span class="gp">... </span>                    <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;translated&quot;</span><span class="p">}}},</span> <span class="p">[]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>
+<span class="go">         &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Alias&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+<span class="go">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+<span class="go">                       &#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">Test Log: {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+<span class="go">           &#39;content&#39;: &#39;Test Message&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+                        <input id="mod-util-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-util-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">  1</span></a><span class="sd">&quot;&quot;&quot;Provide utility plugins for all kinds of systems.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">  2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">  3</span></a><span class="sd">- Log logs messages on stdout.</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">  4</span></a><span class="sd">- Init sends list of messages on startup and on demand.</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">  5</span></a><span class="sd">- Execute sends configurable list of messages on demand.</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">  6</span></a><span class="sd">- Alias translates messages to an alias.</span>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">  7</span></a>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">  8</span></a><span class="sd">&gt;&gt;&gt; import controlpi</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">  9</span></a><span class="sd">&gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="sd">...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="sd">...                   &quot;filter&quot;: [{&quot;sender&quot;: {&quot;const&quot;: &quot;Test Alias&quot;}}]},</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a><span class="sd">...      &quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a><span class="sd">...                    &quot;messages&quot;: [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;}]},</span>
+</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="sd">...      &quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a><span class="sd">...                     &quot;from&quot;: {&quot;sender&quot;: {&quot;const&quot;: &quot;Test Init&quot;},</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="sd">...                              &quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="sd">...                     &quot;to&quot;: {&quot;id&quot;: &quot;translated&quot;}}}, []))</span>
+</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="sd">... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a><span class="sd">         &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>
+</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a><span class="sd">         &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Alias&#39;}}]}</span>
+</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a><span class="sd">         &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a><span class="sd">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a><span class="sd">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}}],</span>
+</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a><span class="sd">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="sd">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="sd">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a><span class="sd">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>
+</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="sd">         &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a><span class="sd">                       &#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42,</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a><span class="sd">         &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a><span class="sd">         &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a><span class="sd">Test Log: {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a><span class="sd">           &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a>
+</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span>
+</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a>
+</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi</span><span class="w"> </span><span class="kn">import</span> <span class="n">BasePlugin</span><span class="p">,</span> <span class="n">Message</span><span class="p">,</span> <span class="n">MessageTemplate</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a>
+</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">List</span>
+</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a>
+</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a>
+</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Log</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Log messages on stdout.</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a>
+</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a><span class="sd">    The &quot;filter&quot; configuration key gets a list of message templates defining</span>
+</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a><span class="sd">    the messages that should be logged by the plugin instance.</span>
+</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a>
+</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a><span class="sd">    In the following example the first and third message match the given</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a><span class="sd">    template and are logged by the instance &quot;Test Log&quot;, while the second</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a><span class="sd">    message does not match and is only logged by the test, but not by the</span>
+</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a><span class="sd">    Log instance:</span>
+</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="sd">    ...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="sd">    ...                   &quot;filter&quot;: [{&quot;id&quot;: {&quot;const&quot;: 42}}]}},</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="sd">    ...     [{&quot;id&quot;: 42, &quot;message&quot;: &quot;Test Message&quot;},</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a><span class="sd">    ...      {&quot;id&quot;: 42.42, &quot;message&quot;: &quot;Second Message&quot;},</span>
+</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="sd">    ...      {&quot;id&quot;: 42, &quot;message&quot;: &quot;Third Message&quot;}]))</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a><span class="sd">             &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>
+</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a><span class="sd">             &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a><span class="sd">    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42.42, &#39;message&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a><span class="sd">    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>
+</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a>
+</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a><span class="sd">    The &quot;filter&quot; key is required:</span>
+</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd">    ...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;}}, []))</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd">    data must contain [&#39;filter&#39;] properties</span>
+</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd">    Configuration for &#39;Test Log&#39; is not valid.</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a>
+</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a><span class="sd">    The &quot;filter&quot; key has to contain a list of message templates, i.e.,</span>
+</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a><span class="sd">    JSON objects:</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a><span class="sd">    ...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a><span class="sd">    ...                   &quot;filter&quot;: [42]}}, []))</span>
+</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a><span class="sd">    data.filter[0] must be object</span>
+</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a><span class="sd">    Configuration for &#39;Test Log&#39; is not valid.</span>
+</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a>
+</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}}},</span>
+</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;filter&quot;</span><span class="p">],</span>
+</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a>    <span class="p">}</span>
+</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Log plugin configuration.</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a>
+</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a>
+</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a><span class="sd">    - &#39;filter&#39;: list of message templates to be logged.</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a>
+</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;filter&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_log</span><span class="p">)])</span>
+</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a>
+</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_log</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a>
+</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a>        <span class="k">pass</span>
+</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a>
+</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a>
+</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Init</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send list of messages on startup and on demand.</span>
+</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a>
+</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="sd">    The &quot;messages&quot; configuration key gets a list of messages to be sent on</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="sd">    startup. The same list is sent in reaction to a message with</span>
+</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a><span class="sd">    &quot;target&quot;: NAME and &quot;command&quot;: &quot;execute&quot;.</span>
+</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a>
+</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="sd">    In the example, the two configured messages are sent twice, once at</span>
+</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd">    startup and a second time in reaction to the &quot;execute&quot; command sent by</span>
+</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd">    the test:</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd">    ...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd">    ...                    &quot;messages&quot;: [{&quot;id&quot;: 42,</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="sd">    ...                                  &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd">    ...                                 {&quot;id&quot;: 42.42,</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd">    ...                                  &quot;content&quot;: &quot;Second Message&quot;}]}},</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Init&quot;, &quot;command&quot;: &quot;execute&quot;}]))</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="sd">             &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>
+</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a><span class="sd">                       {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>
+</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Init&#39;, &#39;command&#39;: &#39;execute&#39;}</span>
+</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a>
+</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a><span class="sd">    The &quot;messages&quot; key is required:</span>
+</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a><span class="sd">    ...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;}}, []))</span>
+</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a><span class="sd">    data must contain [&#39;messages&#39;] properties</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a><span class="sd">    Configuration for &#39;Test Init&#39; is not valid.</span>
+</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a>
+</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a><span class="sd">    The &quot;messages&quot; key has to contain a list of (partial) messages, i.e.,</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a><span class="sd">    JSON objects:</span>
+</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="sd">    ...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="sd">    ...                    &quot;messages&quot;: [42]}}, []))</span>
+</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="sd">    data.messages[0] must be object</span>
+</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a><span class="sd">    Configuration for &#39;Test Init&#39; is not valid.</span>
+</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a>
+</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}}},</span>
+</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">],</span>
+</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a>    <span class="p">}</span>
+</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Init plugin configuration.</span>
+</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a>
+</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a>
+</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a><span class="sd">    - &#39;messages&#39;: list of messages to be sent.</span>
+</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a>
+</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a>            <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a>            <span class="p">[</span>
+</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a>                <span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a>                <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]</span>
+</span><span id="L-181"><a href="#L-181"><span class="linenos">181</span></a>            <span class="p">],</span>
+</span><span id="L-182"><a href="#L-182"><span class="linenos">182</span></a>            <span class="p">[</span>
+</span><span id="L-183"><a href="#L-183"><span class="linenos">183</span></a>                <span class="p">(</span>
+</span><span id="L-184"><a href="#L-184"><span class="linenos">184</span></a>                    <span class="p">[</span>
+</span><span id="L-185"><a href="#L-185"><span class="linenos">185</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-186"><a href="#L-186"><span class="linenos">186</span></a>                            <span class="p">{</span>
+</span><span id="L-187"><a href="#L-187"><span class="linenos">187</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-188"><a href="#L-188"><span class="linenos">188</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">},</span>
+</span><span id="L-189"><a href="#L-189"><span class="linenos">189</span></a>                            <span class="p">}</span>
+</span><span id="L-190"><a href="#L-190"><span class="linenos">190</span></a>                        <span class="p">)</span>
+</span><span id="L-191"><a href="#L-191"><span class="linenos">191</span></a>                    <span class="p">],</span>
+</span><span id="L-192"><a href="#L-192"><span class="linenos">192</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_execute</span><span class="p">,</span>
+</span><span id="L-193"><a href="#L-193"><span class="linenos">193</span></a>                <span class="p">)</span>
+</span><span id="L-194"><a href="#L-194"><span class="linenos">194</span></a>            <span class="p">],</span>
+</span><span id="L-195"><a href="#L-195"><span class="linenos">195</span></a>        <span class="p">)</span>
+</span><span id="L-196"><a href="#L-196"><span class="linenos">196</span></a>
+</span><span id="L-197"><a href="#L-197"><span class="linenos">197</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-198"><a href="#L-198"><span class="linenos">198</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]:</span>
+</span><span id="L-199"><a href="#L-199"><span class="linenos">199</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="L-200"><a href="#L-200"><span class="linenos">200</span></a>            <span class="c1"># Give immediate reactions to messages opportunity to happen:</span>
+</span><span id="L-201"><a href="#L-201"><span class="linenos">201</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="L-202"><a href="#L-202"><span class="linenos">202</span></a>
+</span><span id="L-203"><a href="#L-203"><span class="linenos">203</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-204"><a href="#L-204"><span class="linenos">204</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send configured messages on startup.&quot;&quot;&quot;</span>
+</span><span id="L-205"><a href="#L-205"><span class="linenos">205</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]:</span>
+</span><span id="L-206"><a href="#L-206"><span class="linenos">206</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="L-207"><a href="#L-207"><span class="linenos">207</span></a>
+</span><span id="L-208"><a href="#L-208"><span class="linenos">208</span></a>
+</span><span id="L-209"><a href="#L-209"><span class="linenos">209</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Execute</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-210"><a href="#L-210"><span class="linenos">210</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send configurable list of messages on demand.</span>
+</span><span id="L-211"><a href="#L-211"><span class="linenos">211</span></a>
+</span><span id="L-212"><a href="#L-212"><span class="linenos">212</span></a><span class="sd">    An Execute plugin instance receives two kinds of commands.</span>
+</span><span id="L-213"><a href="#L-213"><span class="linenos">213</span></a><span class="sd">    The &quot;set messages&quot; command has a &quot;messages&quot; key with a list of (partial)</span>
+</span><span id="L-214"><a href="#L-214"><span class="linenos">214</span></a><span class="sd">    messages, which are sent by the Execute instance in reaction to an</span>
+</span><span id="L-215"><a href="#L-215"><span class="linenos">215</span></a><span class="sd">    &quot;execute&quot; command.</span>
+</span><span id="L-216"><a href="#L-216"><span class="linenos">216</span></a>
+</span><span id="L-217"><a href="#L-217"><span class="linenos">217</span></a><span class="sd">    In the example, the first command sent by the test sets two messages,</span>
+</span><span id="L-218"><a href="#L-218"><span class="linenos">218</span></a><span class="sd">    which are then sent in reaction to the second command sent by the test:</span>
+</span><span id="L-219"><a href="#L-219"><span class="linenos">219</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-220"><a href="#L-220"><span class="linenos">220</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-221"><a href="#L-221"><span class="linenos">221</span></a><span class="sd">    ...     {&quot;Test Execute&quot;: {&quot;plugin&quot;: &quot;Execute&quot;}},</span>
+</span><span id="L-222"><a href="#L-222"><span class="linenos">222</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Execute&quot;, &quot;command&quot;: &quot;set messages&quot;,</span>
+</span><span id="L-223"><a href="#L-223"><span class="linenos">223</span></a><span class="sd">    ...       &quot;messages&quot;: [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="L-224"><a href="#L-224"><span class="linenos">224</span></a><span class="sd">    ...                    {&quot;id&quot;: 42.42, &quot;content&quot;: &quot;Second Message&quot;}]},</span>
+</span><span id="L-225"><a href="#L-225"><span class="linenos">225</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Execute&quot;, &quot;command&quot;: &quot;execute&quot;}]))</span>
+</span><span id="L-226"><a href="#L-226"><span class="linenos">226</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-227"><a href="#L-227"><span class="linenos">227</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-228"><a href="#L-228"><span class="linenos">228</span></a><span class="sd">             &#39;client&#39;: &#39;Test Execute&#39;, &#39;plugin&#39;: &#39;Execute&#39;,</span>
+</span><span id="L-229"><a href="#L-229"><span class="linenos">229</span></a><span class="sd">             &#39;sends&#39;: [{}],</span>
+</span><span id="L-230"><a href="#L-230"><span class="linenos">230</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>
+</span><span id="L-231"><a href="#L-231"><span class="linenos">231</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},</span>
+</span><span id="L-232"><a href="#L-232"><span class="linenos">232</span></a><span class="sd">                           &#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+</span><span id="L-233"><a href="#L-233"><span class="linenos">233</span></a><span class="sd">                                        &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},</span>
+</span><span id="L-234"><a href="#L-234"><span class="linenos">234</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>
+</span><span id="L-235"><a href="#L-235"><span class="linenos">235</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="L-236"><a href="#L-236"><span class="linenos">236</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>
+</span><span id="L-237"><a href="#L-237"><span class="linenos">237</span></a><span class="sd">             &#39;command&#39;: &#39;set messages&#39;,</span>
+</span><span id="L-238"><a href="#L-238"><span class="linenos">238</span></a><span class="sd">             &#39;messages&#39;: [{&#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;},</span>
+</span><span id="L-239"><a href="#L-239"><span class="linenos">239</span></a><span class="sd">                          {&#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}]}</span>
+</span><span id="L-240"><a href="#L-240"><span class="linenos">240</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>
+</span><span id="L-241"><a href="#L-241"><span class="linenos">241</span></a><span class="sd">             &#39;command&#39;: &#39;execute&#39;}</span>
+</span><span id="L-242"><a href="#L-242"><span class="linenos">242</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42,</span>
+</span><span id="L-243"><a href="#L-243"><span class="linenos">243</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="L-244"><a href="#L-244"><span class="linenos">244</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42.42,</span>
+</span><span id="L-245"><a href="#L-245"><span class="linenos">245</span></a><span class="sd">             &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="L-246"><a href="#L-246"><span class="linenos">246</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-247"><a href="#L-247"><span class="linenos">247</span></a>
+</span><span id="L-248"><a href="#L-248"><span class="linenos">248</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="L-249"><a href="#L-249"><span class="linenos">249</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Execute plugin configuration.</span>
+</span><span id="L-250"><a href="#L-250"><span class="linenos">250</span></a>
+</span><span id="L-251"><a href="#L-251"><span class="linenos">251</span></a><span class="sd">    There are no required or optional configuration keys.</span>
+</span><span id="L-252"><a href="#L-252"><span class="linenos">252</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-253"><a href="#L-253"><span class="linenos">253</span></a>
+</span><span id="L-254"><a href="#L-254"><span class="linenos">254</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-255"><a href="#L-255"><span class="linenos">255</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-256"><a href="#L-256"><span class="linenos">256</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Message</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-257"><a href="#L-257"><span class="linenos">257</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-258"><a href="#L-258"><span class="linenos">258</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-259"><a href="#L-259"><span class="linenos">259</span></a>            <span class="s2">&quot;Execute&quot;</span><span class="p">,</span>
+</span><span id="L-260"><a href="#L-260"><span class="linenos">260</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">()],</span>
+</span><span id="L-261"><a href="#L-261"><span class="linenos">261</span></a>            <span class="p">[</span>
+</span><span id="L-262"><a href="#L-262"><span class="linenos">262</span></a>                <span class="p">(</span>
+</span><span id="L-263"><a href="#L-263"><span class="linenos">263</span></a>                    <span class="p">[</span>
+</span><span id="L-264"><a href="#L-264"><span class="linenos">264</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-265"><a href="#L-265"><span class="linenos">265</span></a>                            <span class="p">{</span>
+</span><span id="L-266"><a href="#L-266"><span class="linenos">266</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-267"><a href="#L-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set messages&quot;</span><span class="p">},</span>
+</span><span id="L-268"><a href="#L-268"><span class="linenos">268</span></a>                                <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-269"><a href="#L-269"><span class="linenos">269</span></a>                                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="L-270"><a href="#L-270"><span class="linenos">270</span></a>                                    <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="L-271"><a href="#L-271"><span class="linenos">271</span></a>                                <span class="p">},</span>
+</span><span id="L-272"><a href="#L-272"><span class="linenos">272</span></a>                            <span class="p">}</span>
+</span><span id="L-273"><a href="#L-273"><span class="linenos">273</span></a>                        <span class="p">)</span>
+</span><span id="L-274"><a href="#L-274"><span class="linenos">274</span></a>                    <span class="p">],</span>
+</span><span id="L-275"><a href="#L-275"><span class="linenos">275</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_messages</span><span class="p">,</span>
+</span><span id="L-276"><a href="#L-276"><span class="linenos">276</span></a>                <span class="p">),</span>
+</span><span id="L-277"><a href="#L-277"><span class="linenos">277</span></a>                <span class="p">(</span>
+</span><span id="L-278"><a href="#L-278"><span class="linenos">278</span></a>                    <span class="p">[</span>
+</span><span id="L-279"><a href="#L-279"><span class="linenos">279</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-280"><a href="#L-280"><span class="linenos">280</span></a>                            <span class="p">{</span>
+</span><span id="L-281"><a href="#L-281"><span class="linenos">281</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-282"><a href="#L-282"><span class="linenos">282</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">},</span>
+</span><span id="L-283"><a href="#L-283"><span class="linenos">283</span></a>                            <span class="p">}</span>
+</span><span id="L-284"><a href="#L-284"><span class="linenos">284</span></a>                        <span class="p">)</span>
+</span><span id="L-285"><a href="#L-285"><span class="linenos">285</span></a>                    <span class="p">],</span>
+</span><span id="L-286"><a href="#L-286"><span class="linenos">286</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_execute</span><span class="p">,</span>
+</span><span id="L-287"><a href="#L-287"><span class="linenos">287</span></a>                <span class="p">),</span>
+</span><span id="L-288"><a href="#L-288"><span class="linenos">288</span></a>            <span class="p">],</span>
+</span><span id="L-289"><a href="#L-289"><span class="linenos">289</span></a>        <span class="p">)</span>
+</span><span id="L-290"><a href="#L-290"><span class="linenos">290</span></a>
+</span><span id="L-291"><a href="#L-291"><span class="linenos">291</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_set_messages</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-292"><a href="#L-292"><span class="linenos">292</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">],</span> <span class="nb">list</span><span class="p">)</span>
+</span><span id="L-293"><a href="#L-293"><span class="linenos">293</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">messages</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">])</span>
+</span><span id="L-294"><a href="#L-294"><span class="linenos">294</span></a>
+</span><span id="L-295"><a href="#L-295"><span class="linenos">295</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-296"><a href="#L-296"><span class="linenos">296</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
+</span><span id="L-297"><a href="#L-297"><span class="linenos">297</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="L-298"><a href="#L-298"><span class="linenos">298</span></a>            <span class="c1"># Give immediate reactions to messages opportunity to happen:</span>
+</span><span id="L-299"><a href="#L-299"><span class="linenos">299</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="L-300"><a href="#L-300"><span class="linenos">300</span></a>
+</span><span id="L-301"><a href="#L-301"><span class="linenos">301</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-302"><a href="#L-302"><span class="linenos">302</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-303"><a href="#L-303"><span class="linenos">303</span></a>        <span class="k">pass</span>
+</span><span id="L-304"><a href="#L-304"><span class="linenos">304</span></a>
+</span><span id="L-305"><a href="#L-305"><span class="linenos">305</span></a>
+</span><span id="L-306"><a href="#L-306"><span class="linenos">306</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Alias</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-307"><a href="#L-307"><span class="linenos">307</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Translate messages to an alias.</span>
+</span><span id="L-308"><a href="#L-308"><span class="linenos">308</span></a>
+</span><span id="L-309"><a href="#L-309"><span class="linenos">309</span></a><span class="sd">    The &quot;from&quot; configuration key gets a message template and the</span>
+</span><span id="L-310"><a href="#L-310"><span class="linenos">310</span></a><span class="sd">    configuration key &quot;to&quot; a (partial) message. The &quot;translate&quot;</span>
+</span><span id="L-311"><a href="#L-311"><span class="linenos">311</span></a><span class="sd">    configuration key contains pairs of message keys, where the &quot;from&quot;</span>
+</span><span id="L-312"><a href="#L-312"><span class="linenos">312</span></a><span class="sd">    message key is translated to the &quot;to&quot; message key if present in the</span>
+</span><span id="L-313"><a href="#L-313"><span class="linenos">313</span></a><span class="sd">    message.</span>
+</span><span id="L-314"><a href="#L-314"><span class="linenos">314</span></a>
+</span><span id="L-315"><a href="#L-315"><span class="linenos">315</span></a><span class="sd">    All messages matching the &quot;from&quot; template are received by the Alias</span>
+</span><span id="L-316"><a href="#L-316"><span class="linenos">316</span></a><span class="sd">    instance and a message translated by adding the keys and values of the</span>
+</span><span id="L-317"><a href="#L-317"><span class="linenos">317</span></a><span class="sd">    &quot;to&quot; message and the translated key-value pairs according to</span>
+</span><span id="L-318"><a href="#L-318"><span class="linenos">318</span></a><span class="sd">    &quot;translate&quot; is sent. Keys that are not &quot;sender&quot; and not modified by</span>
+</span><span id="L-319"><a href="#L-319"><span class="linenos">319</span></a><span class="sd">    &quot;to&quot; or &quot;translate&quot; are retained.</span>
+</span><span id="L-320"><a href="#L-320"><span class="linenos">320</span></a>
+</span><span id="L-321"><a href="#L-321"><span class="linenos">321</span></a><span class="sd">    In the example, the two messages sent by the test are translated by the</span>
+</span><span id="L-322"><a href="#L-322"><span class="linenos">322</span></a><span class="sd">    Alias instance and the translated messages are sent by it preserving</span>
+</span><span id="L-323"><a href="#L-323"><span class="linenos">323</span></a><span class="sd">    the &quot;content&quot; keys:</span>
+</span><span id="L-324"><a href="#L-324"><span class="linenos">324</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-325"><a href="#L-325"><span class="linenos">325</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-326"><a href="#L-326"><span class="linenos">326</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="L-327"><a href="#L-327"><span class="linenos">327</span></a><span class="sd">    ...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="L-328"><a href="#L-328"><span class="linenos">328</span></a><span class="sd">    ...                     &quot;to&quot;: {&quot;id&quot;: &quot;translated&quot;},</span>
+</span><span id="L-329"><a href="#L-329"><span class="linenos">329</span></a><span class="sd">    ...                     &quot;translate&quot;: [{&#39;from&#39;: &quot;old&quot;, &quot;to&quot;: &quot;new&quot;}]}},</span>
+</span><span id="L-330"><a href="#L-330"><span class="linenos">330</span></a><span class="sd">    ...     [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;, &quot;old&quot;: &quot;content&quot;},</span>
+</span><span id="L-331"><a href="#L-331"><span class="linenos">331</span></a><span class="sd">    ...      {&quot;id&quot;: 42, &quot;content&quot;: &quot;Second Message&quot;, &quot;old&quot;: &quot;content&quot;}]))</span>
+</span><span id="L-332"><a href="#L-332"><span class="linenos">332</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-333"><a href="#L-333"><span class="linenos">333</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-334"><a href="#L-334"><span class="linenos">334</span></a><span class="sd">             &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+</span><span id="L-335"><a href="#L-335"><span class="linenos">335</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>
+</span><span id="L-336"><a href="#L-336"><span class="linenos">336</span></a><span class="sd">             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="L-337"><a href="#L-337"><span class="linenos">337</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+</span><span id="L-338"><a href="#L-338"><span class="linenos">338</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+</span><span id="L-339"><a href="#L-339"><span class="linenos">339</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+</span><span id="L-340"><a href="#L-340"><span class="linenos">340</span></a><span class="sd">             &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+</span><span id="L-341"><a href="#L-341"><span class="linenos">341</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+</span><span id="L-342"><a href="#L-342"><span class="linenos">342</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="L-343"><a href="#L-343"><span class="linenos">343</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+</span><span id="L-344"><a href="#L-344"><span class="linenos">344</span></a><span class="sd">             &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="L-345"><a href="#L-345"><span class="linenos">345</span></a>
+</span><span id="L-346"><a href="#L-346"><span class="linenos">346</span></a><span class="sd">    An Alias instance can also translate to a list of messages instead of</span>
+</span><span id="L-347"><a href="#L-347"><span class="linenos">347</span></a><span class="sd">    a single message:</span>
+</span><span id="L-348"><a href="#L-348"><span class="linenos">348</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-349"><a href="#L-349"><span class="linenos">349</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="L-350"><a href="#L-350"><span class="linenos">350</span></a><span class="sd">    ...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="L-351"><a href="#L-351"><span class="linenos">351</span></a><span class="sd">    ...                     &quot;to&quot;: [{&quot;id&quot;: &quot;first&quot;}, {&quot;id&quot;: &quot;second&quot;}],</span>
+</span><span id="L-352"><a href="#L-352"><span class="linenos">352</span></a><span class="sd">    ...                     &quot;translate&quot;: [{&#39;from&#39;: &quot;old&quot;, &quot;to&quot;: &quot;new&quot;}]}},</span>
+</span><span id="L-353"><a href="#L-353"><span class="linenos">353</span></a><span class="sd">    ...     [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;, &quot;old&quot;: &quot;content&quot;}]))</span>
+</span><span id="L-354"><a href="#L-354"><span class="linenos">354</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-355"><a href="#L-355"><span class="linenos">355</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-356"><a href="#L-356"><span class="linenos">356</span></a><span class="sd">             &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+</span><span id="L-357"><a href="#L-357"><span class="linenos">357</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;first&#39;}},</span>
+</span><span id="L-358"><a href="#L-358"><span class="linenos">358</span></a><span class="sd">                       {&#39;id&#39;: {&#39;const&#39;: &#39;second&#39;}}],</span>
+</span><span id="L-359"><a href="#L-359"><span class="linenos">359</span></a><span class="sd">             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="L-360"><a href="#L-360"><span class="linenos">360</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+</span><span id="L-361"><a href="#L-361"><span class="linenos">361</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+</span><span id="L-362"><a href="#L-362"><span class="linenos">362</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;first&#39;,</span>
+</span><span id="L-363"><a href="#L-363"><span class="linenos">363</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="L-364"><a href="#L-364"><span class="linenos">364</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;second&#39;,</span>
+</span><span id="L-365"><a href="#L-365"><span class="linenos">365</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="L-366"><a href="#L-366"><span class="linenos">366</span></a>
+</span><span id="L-367"><a href="#L-367"><span class="linenos">367</span></a><span class="sd">    The &quot;from&quot; key is required:</span>
+</span><span id="L-368"><a href="#L-368"><span class="linenos">368</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-369"><a href="#L-369"><span class="linenos">369</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;}}, []))</span>
+</span><span id="L-370"><a href="#L-370"><span class="linenos">370</span></a><span class="sd">    data must contain [&#39;from&#39;] properties</span>
+</span><span id="L-371"><a href="#L-371"><span class="linenos">371</span></a><span class="sd">    Configuration for &#39;Test Alias&#39; is not valid.</span>
+</span><span id="L-372"><a href="#L-372"><span class="linenos">372</span></a>
+</span><span id="L-373"><a href="#L-373"><span class="linenos">373</span></a><span class="sd">    The &quot;from&quot; key has to contain a message template and the &quot;to&quot; key a</span>
+</span><span id="L-374"><a href="#L-374"><span class="linenos">374</span></a><span class="sd">    (partial) message, i.e., both have to be JSON objects:</span>
+</span><span id="L-375"><a href="#L-375"><span class="linenos">375</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-376"><a href="#L-376"><span class="linenos">376</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="L-377"><a href="#L-377"><span class="linenos">377</span></a><span class="sd">    ...                     &quot;from&quot;: 42,</span>
+</span><span id="L-378"><a href="#L-378"><span class="linenos">378</span></a><span class="sd">    ...                     &quot;to&quot;: 42}}, []))</span>
+</span><span id="L-379"><a href="#L-379"><span class="linenos">379</span></a><span class="sd">    data.from must be object</span>
+</span><span id="L-380"><a href="#L-380"><span class="linenos">380</span></a><span class="sd">    Configuration for &#39;Test Alias&#39; is not valid.</span>
+</span><span id="L-381"><a href="#L-381"><span class="linenos">381</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-382"><a href="#L-382"><span class="linenos">382</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="L-383"><a href="#L-383"><span class="linenos">383</span></a><span class="sd">    ...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="L-384"><a href="#L-384"><span class="linenos">384</span></a><span class="sd">    ...                     &quot;to&quot;: 42}}, []))</span>
+</span><span id="L-385"><a href="#L-385"><span class="linenos">385</span></a><span class="sd">    data.to cannot be validated by any definition</span>
+</span><span id="L-386"><a href="#L-386"><span class="linenos">386</span></a><span class="sd">    Configuration for &#39;Test Alias&#39; is not valid.</span>
+</span><span id="L-387"><a href="#L-387"><span class="linenos">387</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-388"><a href="#L-388"><span class="linenos">388</span></a>
+</span><span id="L-389"><a href="#L-389"><span class="linenos">389</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-390"><a href="#L-390"><span class="linenos">390</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-391"><a href="#L-391"><span class="linenos">391</span></a>            <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="L-392"><a href="#L-392"><span class="linenos">392</span></a>            <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-393"><a href="#L-393"><span class="linenos">393</span></a>                <span class="s2">&quot;anyOf&quot;</span><span class="p">:</span> <span class="p">[</span>
+</span><span id="L-394"><a href="#L-394"><span class="linenos">394</span></a>                    <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="L-395"><a href="#L-395"><span class="linenos">395</span></a>                    <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}},</span>
+</span><span id="L-396"><a href="#L-396"><span class="linenos">396</span></a>                <span class="p">]</span>
+</span><span id="L-397"><a href="#L-397"><span class="linenos">397</span></a>            <span class="p">},</span>
+</span><span id="L-398"><a href="#L-398"><span class="linenos">398</span></a>            <span class="s2">&quot;translate&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-399"><a href="#L-399"><span class="linenos">399</span></a>                <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="L-400"><a href="#L-400"><span class="linenos">400</span></a>                <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-401"><a href="#L-401"><span class="linenos">401</span></a>                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">,</span>
+</span><span id="L-402"><a href="#L-402"><span class="linenos">402</span></a>                    <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-403"><a href="#L-403"><span class="linenos">403</span></a>                        <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="L-404"><a href="#L-404"><span class="linenos">404</span></a>                        <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="L-405"><a href="#L-405"><span class="linenos">405</span></a>                    <span class="p">},</span>
+</span><span id="L-406"><a href="#L-406"><span class="linenos">406</span></a>                <span class="p">},</span>
+</span><span id="L-407"><a href="#L-407"><span class="linenos">407</span></a>            <span class="p">},</span>
+</span><span id="L-408"><a href="#L-408"><span class="linenos">408</span></a>        <span class="p">},</span>
+</span><span id="L-409"><a href="#L-409"><span class="linenos">409</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">],</span>
+</span><span id="L-410"><a href="#L-410"><span class="linenos">410</span></a>    <span class="p">}</span>
+</span><span id="L-411"><a href="#L-411"><span class="linenos">411</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Alias plugin configuration.</span>
+</span><span id="L-412"><a href="#L-412"><span class="linenos">412</span></a>
+</span><span id="L-413"><a href="#L-413"><span class="linenos">413</span></a><span class="sd">    Required configuration keys:</span>
+</span><span id="L-414"><a href="#L-414"><span class="linenos">414</span></a>
+</span><span id="L-415"><a href="#L-415"><span class="linenos">415</span></a><span class="sd">    - &#39;from&#39;: template of messages to be translated.</span>
+</span><span id="L-416"><a href="#L-416"><span class="linenos">416</span></a>
+</span><span id="L-417"><a href="#L-417"><span class="linenos">417</span></a><span class="sd">    Optional configuration keys:</span>
+</span><span id="L-418"><a href="#L-418"><span class="linenos">418</span></a>
+</span><span id="L-419"><a href="#L-419"><span class="linenos">419</span></a><span class="sd">    - &#39;to&#39;: translated message(s) to be sent.</span>
+</span><span id="L-420"><a href="#L-420"><span class="linenos">420</span></a><span class="sd">    - &#39;translate&#39;: array of pairs of keys to be translated.</span>
+</span><span id="L-421"><a href="#L-421"><span class="linenos">421</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-422"><a href="#L-422"><span class="linenos">422</span></a>
+</span><span id="L-423"><a href="#L-423"><span class="linenos">423</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-424"><a href="#L-424"><span class="linenos">424</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-425"><a href="#L-425"><span class="linenos">425</span></a>        <span class="n">sends</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-426"><a href="#L-426"><span class="linenos">426</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="L-427"><a href="#L-427"><span class="linenos">427</span></a>        <span class="k">if</span> <span class="s2">&quot;to&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+</span><span id="L-428"><a href="#L-428"><span class="linenos">428</span></a>            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">],</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="L-429"><a href="#L-429"><span class="linenos">429</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]</span>
+</span><span id="L-430"><a href="#L-430"><span class="linenos">430</span></a>                <span class="k">for</span> <span class="n">to</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]:</span>
+</span><span id="L-431"><a href="#L-431"><span class="linenos">431</span></a>                    <span class="n">sends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="n">to</span><span class="p">))</span>
+</span><span id="L-432"><a href="#L-432"><span class="linenos">432</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="L-433"><a href="#L-433"><span class="linenos">433</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]]</span>
+</span><span id="L-434"><a href="#L-434"><span class="linenos">434</span></a>                <span class="n">sends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]))</span>
+</span><span id="L-435"><a href="#L-435"><span class="linenos">435</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="L-436"><a href="#L-436"><span class="linenos">436</span></a>        <span class="k">if</span> <span class="s2">&quot;translate&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+</span><span id="L-437"><a href="#L-437"><span class="linenos">437</span></a>            <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;translate&quot;</span><span class="p">]:</span>
+</span><span id="L-438"><a href="#L-438"><span class="linenos">438</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">[</span><span class="n">pair</span><span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">pair</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]</span>
+</span><span id="L-439"><a href="#L-439"><span class="linenos">439</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-440"><a href="#L-440"><span class="linenos">440</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span> <span class="n">sends</span><span class="p">,</span> <span class="p">[([</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">]],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_alias</span><span class="p">)]</span>
+</span><span id="L-441"><a href="#L-441"><span class="linenos">441</span></a>        <span class="p">)</span>
+</span><span id="L-442"><a href="#L-442"><span class="linenos">442</span></a>
+</span><span id="L-443"><a href="#L-443"><span class="linenos">443</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_alias</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-444"><a href="#L-444"><span class="linenos">444</span></a>        <span class="c1"># Prevent endless loop:</span>
+</span><span id="L-445"><a href="#L-445"><span class="linenos">445</span></a>        <span class="k">if</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">:</span>
+</span><span id="L-446"><a href="#L-446"><span class="linenos">446</span></a>            <span class="k">for</span> <span class="n">to</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_to</span><span class="p">:</span>
+</span><span id="L-447"><a href="#L-447"><span class="linenos">447</span></a>                <span class="n">alias_message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
+</span><span id="L-448"><a href="#L-448"><span class="linenos">448</span></a>                <span class="n">alias_message</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">to</span><span class="p">)</span>
+</span><span id="L-449"><a href="#L-449"><span class="linenos">449</span></a>                <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">:</span>
+</span><span id="L-450"><a href="#L-450"><span class="linenos">450</span></a>                    <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="L-451"><a href="#L-451"><span class="linenos">451</span></a>                        <span class="n">alias_message</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">[</span><span class="n">key</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="L-452"><a href="#L-452"><span class="linenos">452</span></a>                <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">alias_message</span><span class="p">)</span>
+</span><span id="L-453"><a href="#L-453"><span class="linenos">453</span></a>
+</span><span id="L-454"><a href="#L-454"><span class="linenos">454</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-455"><a href="#L-455"><span class="linenos">455</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-456"><a href="#L-456"><span class="linenos">456</span></a>        <span class="k">pass</span>
+</span><span id="L-457"><a href="#L-457"><span class="linenos">457</span></a>
+</span><span id="L-458"><a href="#L-458"><span class="linenos">458</span></a>
+</span><span id="L-459"><a href="#L-459"><span class="linenos">459</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Counter</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-460"><a href="#L-460"><span class="linenos">460</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Count messages confirming to a given template.</span>
+</span><span id="L-461"><a href="#L-461"><span class="linenos">461</span></a>
+</span><span id="L-462"><a href="#L-462"><span class="linenos">462</span></a><span class="sd">    The plugin counts messages confirming to the given template. The</span>
+</span><span id="L-463"><a href="#L-463"><span class="linenos">463</span></a><span class="sd">    counter can be queried and reset by commands. The &#39;reset&#39; command also</span>
+</span><span id="L-464"><a href="#L-464"><span class="linenos">464</span></a><span class="sd">    queries the last count before the reset:</span>
+</span><span id="L-465"><a href="#L-465"><span class="linenos">465</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-466"><a href="#L-466"><span class="linenos">466</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-467"><a href="#L-467"><span class="linenos">467</span></a><span class="sd">    ...     {&quot;Test Counter&quot;: {&quot;plugin&quot;: &quot;Counter&quot;,</span>
+</span><span id="L-468"><a href="#L-468"><span class="linenos">468</span></a><span class="sd">    ...                       &quot;count&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}}}},</span>
+</span><span id="L-469"><a href="#L-469"><span class="linenos">469</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;},</span>
+</span><span id="L-470"><a href="#L-470"><span class="linenos">470</span></a><span class="sd">    ...      {&quot;id&quot;: 42}, {&quot;id&quot;: 42}, {&quot;id&quot;: 49},</span>
+</span><span id="L-471"><a href="#L-471"><span class="linenos">471</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;},</span>
+</span><span id="L-472"><a href="#L-472"><span class="linenos">472</span></a><span class="sd">    ...      {&quot;id&quot;: 42}, {&quot;id&quot;: 42}, {&quot;id&quot;: 42},</span>
+</span><span id="L-473"><a href="#L-473"><span class="linenos">473</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;reset&quot;},</span>
+</span><span id="L-474"><a href="#L-474"><span class="linenos">474</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;},</span>
+</span><span id="L-475"><a href="#L-475"><span class="linenos">475</span></a><span class="sd">    ...      {&quot;id&quot;: 42}, {&quot;id&quot;: 42}, {&quot;id&quot;: 42},</span>
+</span><span id="L-476"><a href="#L-476"><span class="linenos">476</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;}]))</span>
+</span><span id="L-477"><a href="#L-477"><span class="linenos">477</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-478"><a href="#L-478"><span class="linenos">478</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-479"><a href="#L-479"><span class="linenos">479</span></a><span class="sd">             &#39;client&#39;: &#39;Test Counter&#39;, &#39;plugin&#39;: &#39;Counter&#39;,</span>
+</span><span id="L-480"><a href="#L-480"><span class="linenos">480</span></a><span class="sd">             &#39;sends&#39;: [{&#39;count&#39;: {&#39;type&#39;: &#39;integer&#39;}}],</span>
+</span><span id="L-481"><a href="#L-481"><span class="linenos">481</span></a><span class="sd">             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}},</span>
+</span><span id="L-482"><a href="#L-482"><span class="linenos">482</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>
+</span><span id="L-483"><a href="#L-483"><span class="linenos">483</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;get count&#39;}},</span>
+</span><span id="L-484"><a href="#L-484"><span class="linenos">484</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>
+</span><span id="L-485"><a href="#L-485"><span class="linenos">485</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;reset&#39;}}]}</span>
+</span><span id="L-486"><a href="#L-486"><span class="linenos">486</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="L-487"><a href="#L-487"><span class="linenos">487</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="L-488"><a href="#L-488"><span class="linenos">488</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-489"><a href="#L-489"><span class="linenos">489</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>
+</span><span id="L-490"><a href="#L-490"><span class="linenos">490</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="L-491"><a href="#L-491"><span class="linenos">491</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-492"><a href="#L-492"><span class="linenos">492</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 49}</span>
+</span><span id="L-493"><a href="#L-493"><span class="linenos">493</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="L-494"><a href="#L-494"><span class="linenos">494</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="L-495"><a href="#L-495"><span class="linenos">495</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-496"><a href="#L-496"><span class="linenos">496</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 2,</span>
+</span><span id="L-497"><a href="#L-497"><span class="linenos">497</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="L-498"><a href="#L-498"><span class="linenos">498</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-499"><a href="#L-499"><span class="linenos">499</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-500"><a href="#L-500"><span class="linenos">500</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="L-501"><a href="#L-501"><span class="linenos">501</span></a><span class="sd">             &#39;command&#39;: &#39;reset&#39;}</span>
+</span><span id="L-502"><a href="#L-502"><span class="linenos">502</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="L-503"><a href="#L-503"><span class="linenos">503</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="L-504"><a href="#L-504"><span class="linenos">504</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 5,</span>
+</span><span id="L-505"><a href="#L-505"><span class="linenos">505</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="L-506"><a href="#L-506"><span class="linenos">506</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-507"><a href="#L-507"><span class="linenos">507</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>
+</span><span id="L-508"><a href="#L-508"><span class="linenos">508</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="L-509"><a href="#L-509"><span class="linenos">509</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-510"><a href="#L-510"><span class="linenos">510</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="L-511"><a href="#L-511"><span class="linenos">511</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="L-512"><a href="#L-512"><span class="linenos">512</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="L-513"><a href="#L-513"><span class="linenos">513</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 3,</span>
+</span><span id="L-514"><a href="#L-514"><span class="linenos">514</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="L-515"><a href="#L-515"><span class="linenos">515</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-516"><a href="#L-516"><span class="linenos">516</span></a>
+</span><span id="L-517"><a href="#L-517"><span class="linenos">517</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-518"><a href="#L-518"><span class="linenos">518</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="L-519"><a href="#L-519"><span class="linenos">519</span></a>            <span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="L-520"><a href="#L-520"><span class="linenos">520</span></a>            <span class="s2">&quot;date format&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">:</span> <span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S&quot;</span><span class="p">},</span>
+</span><span id="L-521"><a href="#L-521"><span class="linenos">521</span></a>        <span class="p">},</span>
+</span><span id="L-522"><a href="#L-522"><span class="linenos">522</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;count&quot;</span><span class="p">],</span>
+</span><span id="L-523"><a href="#L-523"><span class="linenos">523</span></a>    <span class="p">}</span>
+</span><span id="L-524"><a href="#L-524"><span class="linenos">524</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Counter plugin configuration.</span>
+</span><span id="L-525"><a href="#L-525"><span class="linenos">525</span></a>
+</span><span id="L-526"><a href="#L-526"><span class="linenos">526</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-527"><a href="#L-527"><span class="linenos">527</span></a>
+</span><span id="L-528"><a href="#L-528"><span class="linenos">528</span></a><span class="sd">    - &#39;count&#39;: template of messages to be counted.</span>
+</span><span id="L-529"><a href="#L-529"><span class="linenos">529</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-530"><a href="#L-530"><span class="linenos">530</span></a>
+</span><span id="L-531"><a href="#L-531"><span class="linenos">531</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-532"><a href="#L-532"><span class="linenos">532</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-533"><a href="#L-533"><span class="linenos">533</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_since</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="L-534"><a href="#L-534"><span class="linenos">534</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="L-535"><a href="#L-535"><span class="linenos">535</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-536"><a href="#L-536"><span class="linenos">536</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-537"><a href="#L-537"><span class="linenos">537</span></a>            <span class="s2">&quot;Counter&quot;</span><span class="p">,</span>
+</span><span id="L-538"><a href="#L-538"><span class="linenos">538</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;integer&quot;</span><span class="p">}})],</span>
+</span><span id="L-539"><a href="#L-539"><span class="linenos">539</span></a>            <span class="p">[</span>
+</span><span id="L-540"><a href="#L-540"><span class="linenos">540</span></a>                <span class="p">([</span><span class="n">MessageTemplate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;count&quot;</span><span class="p">])],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span><span class="p">),</span>
+</span><span id="L-541"><a href="#L-541"><span class="linenos">541</span></a>                <span class="p">(</span>
+</span><span id="L-542"><a href="#L-542"><span class="linenos">542</span></a>                    <span class="p">[</span>
+</span><span id="L-543"><a href="#L-543"><span class="linenos">543</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-544"><a href="#L-544"><span class="linenos">544</span></a>                            <span class="p">{</span>
+</span><span id="L-545"><a href="#L-545"><span class="linenos">545</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-546"><a href="#L-546"><span class="linenos">546</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">},</span>
+</span><span id="L-547"><a href="#L-547"><span class="linenos">547</span></a>                            <span class="p">}</span>
+</span><span id="L-548"><a href="#L-548"><span class="linenos">548</span></a>                        <span class="p">)</span>
+</span><span id="L-549"><a href="#L-549"><span class="linenos">549</span></a>                    <span class="p">],</span>
+</span><span id="L-550"><a href="#L-550"><span class="linenos">550</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_count</span><span class="p">,</span>
+</span><span id="L-551"><a href="#L-551"><span class="linenos">551</span></a>                <span class="p">),</span>
+</span><span id="L-552"><a href="#L-552"><span class="linenos">552</span></a>                <span class="p">(</span>
+</span><span id="L-553"><a href="#L-553"><span class="linenos">553</span></a>                    <span class="p">[</span>
+</span><span id="L-554"><a href="#L-554"><span class="linenos">554</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-555"><a href="#L-555"><span class="linenos">555</span></a>                            <span class="p">{</span>
+</span><span id="L-556"><a href="#L-556"><span class="linenos">556</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-557"><a href="#L-557"><span class="linenos">557</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;reset&quot;</span><span class="p">},</span>
+</span><span id="L-558"><a href="#L-558"><span class="linenos">558</span></a>                            <span class="p">}</span>
+</span><span id="L-559"><a href="#L-559"><span class="linenos">559</span></a>                        <span class="p">)</span>
+</span><span id="L-560"><a href="#L-560"><span class="linenos">560</span></a>                    <span class="p">],</span>
+</span><span id="L-561"><a href="#L-561"><span class="linenos">561</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_reset</span><span class="p">,</span>
+</span><span id="L-562"><a href="#L-562"><span class="linenos">562</span></a>                <span class="p">),</span>
+</span><span id="L-563"><a href="#L-563"><span class="linenos">563</span></a>            <span class="p">],</span>
+</span><span id="L-564"><a href="#L-564"><span class="linenos">564</span></a>        <span class="p">)</span>
+</span><span id="L-565"><a href="#L-565"><span class="linenos">565</span></a>
+</span><span id="L-566"><a href="#L-566"><span class="linenos">566</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_count</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-567"><a href="#L-567"><span class="linenos">567</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">+=</span> <span class="mi">1</span>
+</span><span id="L-568"><a href="#L-568"><span class="linenos">568</span></a>
+</span><span id="L-569"><a href="#L-569"><span class="linenos">569</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_count</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-570"><a href="#L-570"><span class="linenos">570</span></a>        <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="L-571"><a href="#L-571"><span class="linenos">571</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-572"><a href="#L-572"><span class="linenos">572</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="L-573"><a href="#L-573"><span class="linenos">573</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span><span class="p">,</span> <span class="s2">&quot;since&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_since</span><span class="p">,</span> <span class="s2">&quot;until&quot;</span><span class="p">:</span> <span class="n">now</span><span class="p">}</span>
+</span><span id="L-574"><a href="#L-574"><span class="linenos">574</span></a>            <span class="p">)</span>
+</span><span id="L-575"><a href="#L-575"><span class="linenos">575</span></a>        <span class="p">)</span>
+</span><span id="L-576"><a href="#L-576"><span class="linenos">576</span></a>
+</span><span id="L-577"><a href="#L-577"><span class="linenos">577</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_reset</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-578"><a href="#L-578"><span class="linenos">578</span></a>        <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="L-579"><a href="#L-579"><span class="linenos">579</span></a>        <span class="n">counter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span>
+</span><span id="L-580"><a href="#L-580"><span class="linenos">580</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="L-581"><a href="#L-581"><span class="linenos">581</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-582"><a href="#L-582"><span class="linenos">582</span></a>            <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="n">counter</span><span class="p">,</span> <span class="s2">&quot;since&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_since</span><span class="p">,</span> <span class="s2">&quot;until&quot;</span><span class="p">:</span> <span class="n">now</span><span class="p">})</span>
+</span><span id="L-583"><a href="#L-583"><span class="linenos">583</span></a>        <span class="p">)</span>
+</span><span id="L-584"><a href="#L-584"><span class="linenos">584</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_since</span> <span class="o">=</span> <span class="n">now</span>
+</span><span id="L-585"><a href="#L-585"><span class="linenos">585</span></a>
+</span><span id="L-586"><a href="#L-586"><span class="linenos">586</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-587"><a href="#L-587"><span class="linenos">587</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-588"><a href="#L-588"><span class="linenos">588</span></a>        <span class="k">pass</span>
+</span><span id="L-589"><a href="#L-589"><span class="linenos">589</span></a>
+</span><span id="L-590"><a href="#L-590"><span class="linenos">590</span></a>
+</span><span id="L-591"><a href="#L-591"><span class="linenos">591</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Date</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-592"><a href="#L-592"><span class="linenos">592</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send message with current date.</span>
+</span><span id="L-593"><a href="#L-593"><span class="linenos">593</span></a>
+</span><span id="L-594"><a href="#L-594"><span class="linenos">594</span></a><span class="sd">    The plugin reacts to &#39;get date&#39; commands by sending messages with</span>
+</span><span id="L-595"><a href="#L-595"><span class="linenos">595</span></a><span class="sd">    a &#39;date&#39; key:</span>
+</span><span id="L-596"><a href="#L-596"><span class="linenos">596</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-597"><a href="#L-597"><span class="linenos">597</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-598"><a href="#L-598"><span class="linenos">598</span></a><span class="sd">    ...     {&quot;Test Date&quot;: {&quot;plugin&quot;: &quot;Date&quot;}},</span>
+</span><span id="L-599"><a href="#L-599"><span class="linenos">599</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Date&quot;, &quot;command&quot;: &quot;get date&quot;}]))</span>
+</span><span id="L-600"><a href="#L-600"><span class="linenos">600</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-601"><a href="#L-601"><span class="linenos">601</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-602"><a href="#L-602"><span class="linenos">602</span></a><span class="sd">             &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>
+</span><span id="L-603"><a href="#L-603"><span class="linenos">603</span></a><span class="sd">             &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-604"><a href="#L-604"><span class="linenos">604</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>
+</span><span id="L-605"><a href="#L-605"><span class="linenos">605</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>
+</span><span id="L-606"><a href="#L-606"><span class="linenos">606</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>
+</span><span id="L-607"><a href="#L-607"><span class="linenos">607</span></a><span class="sd">             &#39;command&#39;: &#39;get date&#39;}</span>
+</span><span id="L-608"><a href="#L-608"><span class="linenos">608</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>
+</span><span id="L-609"><a href="#L-609"><span class="linenos">609</span></a>
+</span><span id="L-610"><a href="#L-610"><span class="linenos">610</span></a><span class="sd">    The format of the date can be configured with the &#39;format&#39;</span>
+</span><span id="L-611"><a href="#L-611"><span class="linenos">611</span></a><span class="sd">    configuration key:</span>
+</span><span id="L-612"><a href="#L-612"><span class="linenos">612</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-613"><a href="#L-613"><span class="linenos">613</span></a><span class="sd">    ...     {&quot;Test Date&quot;: {&quot;plugin&quot;: &quot;Date&quot;,</span>
+</span><span id="L-614"><a href="#L-614"><span class="linenos">614</span></a><span class="sd">    ...                    &quot;format&quot;: &quot;%Y%m%d%H%M%S%f&quot;}},</span>
+</span><span id="L-615"><a href="#L-615"><span class="linenos">615</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Date&quot;, &quot;command&quot;: &quot;get date&quot;}]))</span>
+</span><span id="L-616"><a href="#L-616"><span class="linenos">616</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="L-617"><a href="#L-617"><span class="linenos">617</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-618"><a href="#L-618"><span class="linenos">618</span></a><span class="sd">             &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>
+</span><span id="L-619"><a href="#L-619"><span class="linenos">619</span></a><span class="sd">             &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-620"><a href="#L-620"><span class="linenos">620</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>
+</span><span id="L-621"><a href="#L-621"><span class="linenos">621</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>
+</span><span id="L-622"><a href="#L-622"><span class="linenos">622</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>
+</span><span id="L-623"><a href="#L-623"><span class="linenos">623</span></a><span class="sd">             &#39;command&#39;: &#39;get date&#39;}</span>
+</span><span id="L-624"><a href="#L-624"><span class="linenos">624</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>
+</span><span id="L-625"><a href="#L-625"><span class="linenos">625</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-626"><a href="#L-626"><span class="linenos">626</span></a>
+</span><span id="L-627"><a href="#L-627"><span class="linenos">627</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-628"><a href="#L-628"><span class="linenos">628</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">:</span> <span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S&quot;</span><span class="p">}}</span>
+</span><span id="L-629"><a href="#L-629"><span class="linenos">629</span></a>    <span class="p">}</span>
+</span><span id="L-630"><a href="#L-630"><span class="linenos">630</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Date plugin configuration.</span>
+</span><span id="L-631"><a href="#L-631"><span class="linenos">631</span></a>
+</span><span id="L-632"><a href="#L-632"><span class="linenos">632</span></a><span class="sd">    Optional configuration key:</span>
+</span><span id="L-633"><a href="#L-633"><span class="linenos">633</span></a>
+</span><span id="L-634"><a href="#L-634"><span class="linenos">634</span></a><span class="sd">    - &#39;format&#39;: format for the sent datetime string.</span>
+</span><span id="L-635"><a href="#L-635"><span class="linenos">635</span></a><span class="sd">                Default: &#39;%Y-%m-%d %H:%M:%S&#39;</span>
+</span><span id="L-636"><a href="#L-636"><span class="linenos">636</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-637"><a href="#L-637"><span class="linenos">637</span></a>
+</span><span id="L-638"><a href="#L-638"><span class="linenos">638</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-639"><a href="#L-639"><span class="linenos">639</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-640"><a href="#L-640"><span class="linenos">640</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-641"><a href="#L-641"><span class="linenos">641</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-642"><a href="#L-642"><span class="linenos">642</span></a>            <span class="s2">&quot;Date&quot;</span><span class="p">,</span>
+</span><span id="L-643"><a href="#L-643"><span class="linenos">643</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}})],</span>
+</span><span id="L-644"><a href="#L-644"><span class="linenos">644</span></a>            <span class="p">[</span>
+</span><span id="L-645"><a href="#L-645"><span class="linenos">645</span></a>                <span class="p">(</span>
+</span><span id="L-646"><a href="#L-646"><span class="linenos">646</span></a>                    <span class="p">[</span>
+</span><span id="L-647"><a href="#L-647"><span class="linenos">647</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-648"><a href="#L-648"><span class="linenos">648</span></a>                            <span class="p">{</span>
+</span><span id="L-649"><a href="#L-649"><span class="linenos">649</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-650"><a href="#L-650"><span class="linenos">650</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get date&quot;</span><span class="p">},</span>
+</span><span id="L-651"><a href="#L-651"><span class="linenos">651</span></a>                            <span class="p">}</span>
+</span><span id="L-652"><a href="#L-652"><span class="linenos">652</span></a>                        <span class="p">)</span>
+</span><span id="L-653"><a href="#L-653"><span class="linenos">653</span></a>                    <span class="p">],</span>
+</span><span id="L-654"><a href="#L-654"><span class="linenos">654</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_date</span><span class="p">,</span>
+</span><span id="L-655"><a href="#L-655"><span class="linenos">655</span></a>                <span class="p">)</span>
+</span><span id="L-656"><a href="#L-656"><span class="linenos">656</span></a>            <span class="p">],</span>
+</span><span id="L-657"><a href="#L-657"><span class="linenos">657</span></a>        <span class="p">)</span>
+</span><span id="L-658"><a href="#L-658"><span class="linenos">658</span></a>
+</span><span id="L-659"><a href="#L-659"><span class="linenos">659</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_date</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-660"><a href="#L-660"><span class="linenos">660</span></a>        <span class="n">date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">])</span>
+</span><span id="L-661"><a href="#L-661"><span class="linenos">661</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="n">date</span><span class="p">}))</span>
+</span><span id="L-662"><a href="#L-662"><span class="linenos">662</span></a>
+</span><span id="L-663"><a href="#L-663"><span class="linenos">663</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-664"><a href="#L-664"><span class="linenos">664</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-665"><a href="#L-665"><span class="linenos">665</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="Log">
+                            <input id="Log-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Log</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Log-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Log"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Log-50"><a href="#Log-50"><span class="linenos"> 50</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Log</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Log-51"><a href="#Log-51"><span class="linenos"> 51</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Log messages on stdout.</span>
+</span><span id="Log-52"><a href="#Log-52"><span class="linenos"> 52</span></a>
+</span><span id="Log-53"><a href="#Log-53"><span class="linenos"> 53</span></a><span class="sd">    The &quot;filter&quot; configuration key gets a list of message templates defining</span>
+</span><span id="Log-54"><a href="#Log-54"><span class="linenos"> 54</span></a><span class="sd">    the messages that should be logged by the plugin instance.</span>
+</span><span id="Log-55"><a href="#Log-55"><span class="linenos"> 55</span></a>
+</span><span id="Log-56"><a href="#Log-56"><span class="linenos"> 56</span></a><span class="sd">    In the following example the first and third message match the given</span>
+</span><span id="Log-57"><a href="#Log-57"><span class="linenos"> 57</span></a><span class="sd">    template and are logged by the instance &quot;Test Log&quot;, while the second</span>
+</span><span id="Log-58"><a href="#Log-58"><span class="linenos"> 58</span></a><span class="sd">    message does not match and is only logged by the test, but not by the</span>
+</span><span id="Log-59"><a href="#Log-59"><span class="linenos"> 59</span></a><span class="sd">    Log instance:</span>
+</span><span id="Log-60"><a href="#Log-60"><span class="linenos"> 60</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Log-61"><a href="#Log-61"><span class="linenos"> 61</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Log-62"><a href="#Log-62"><span class="linenos"> 62</span></a><span class="sd">    ...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="Log-63"><a href="#Log-63"><span class="linenos"> 63</span></a><span class="sd">    ...                   &quot;filter&quot;: [{&quot;id&quot;: {&quot;const&quot;: 42}}]}},</span>
+</span><span id="Log-64"><a href="#Log-64"><span class="linenos"> 64</span></a><span class="sd">    ...     [{&quot;id&quot;: 42, &quot;message&quot;: &quot;Test Message&quot;},</span>
+</span><span id="Log-65"><a href="#Log-65"><span class="linenos"> 65</span></a><span class="sd">    ...      {&quot;id&quot;: 42.42, &quot;message&quot;: &quot;Second Message&quot;},</span>
+</span><span id="Log-66"><a href="#Log-66"><span class="linenos"> 66</span></a><span class="sd">    ...      {&quot;id&quot;: 42, &quot;message&quot;: &quot;Third Message&quot;}]))</span>
+</span><span id="Log-67"><a href="#Log-67"><span class="linenos"> 67</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Log-68"><a href="#Log-68"><span class="linenos"> 68</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Log-69"><a href="#Log-69"><span class="linenos"> 69</span></a><span class="sd">             &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>
+</span><span id="Log-70"><a href="#Log-70"><span class="linenos"> 70</span></a><span class="sd">             &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="Log-71"><a href="#Log-71"><span class="linenos"> 71</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>
+</span><span id="Log-72"><a href="#Log-72"><span class="linenos"> 72</span></a><span class="sd">    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>
+</span><span id="Log-73"><a href="#Log-73"><span class="linenos"> 73</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42.42, &#39;message&#39;: &#39;Second Message&#39;}</span>
+</span><span id="Log-74"><a href="#Log-74"><span class="linenos"> 74</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>
+</span><span id="Log-75"><a href="#Log-75"><span class="linenos"> 75</span></a><span class="sd">    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>
+</span><span id="Log-76"><a href="#Log-76"><span class="linenos"> 76</span></a>
+</span><span id="Log-77"><a href="#Log-77"><span class="linenos"> 77</span></a><span class="sd">    The &quot;filter&quot; key is required:</span>
+</span><span id="Log-78"><a href="#Log-78"><span class="linenos"> 78</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Log-79"><a href="#Log-79"><span class="linenos"> 79</span></a><span class="sd">    ...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;}}, []))</span>
+</span><span id="Log-80"><a href="#Log-80"><span class="linenos"> 80</span></a><span class="sd">    data must contain [&#39;filter&#39;] properties</span>
+</span><span id="Log-81"><a href="#Log-81"><span class="linenos"> 81</span></a><span class="sd">    Configuration for &#39;Test Log&#39; is not valid.</span>
+</span><span id="Log-82"><a href="#Log-82"><span class="linenos"> 82</span></a>
+</span><span id="Log-83"><a href="#Log-83"><span class="linenos"> 83</span></a><span class="sd">    The &quot;filter&quot; key has to contain a list of message templates, i.e.,</span>
+</span><span id="Log-84"><a href="#Log-84"><span class="linenos"> 84</span></a><span class="sd">    JSON objects:</span>
+</span><span id="Log-85"><a href="#Log-85"><span class="linenos"> 85</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Log-86"><a href="#Log-86"><span class="linenos"> 86</span></a><span class="sd">    ...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,</span>
+</span><span id="Log-87"><a href="#Log-87"><span class="linenos"> 87</span></a><span class="sd">    ...                   &quot;filter&quot;: [42]}}, []))</span>
+</span><span id="Log-88"><a href="#Log-88"><span class="linenos"> 88</span></a><span class="sd">    data.filter[0] must be object</span>
+</span><span id="Log-89"><a href="#Log-89"><span class="linenos"> 89</span></a><span class="sd">    Configuration for &#39;Test Log&#39; is not valid.</span>
+</span><span id="Log-90"><a href="#Log-90"><span class="linenos"> 90</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Log-91"><a href="#Log-91"><span class="linenos"> 91</span></a>
+</span><span id="Log-92"><a href="#Log-92"><span class="linenos"> 92</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Log-93"><a href="#Log-93"><span class="linenos"> 93</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}}},</span>
+</span><span id="Log-94"><a href="#Log-94"><span class="linenos"> 94</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;filter&quot;</span><span class="p">],</span>
+</span><span id="Log-95"><a href="#Log-95"><span class="linenos"> 95</span></a>    <span class="p">}</span>
+</span><span id="Log-96"><a href="#Log-96"><span class="linenos"> 96</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Log plugin configuration.</span>
+</span><span id="Log-97"><a href="#Log-97"><span class="linenos"> 97</span></a>
+</span><span id="Log-98"><a href="#Log-98"><span class="linenos"> 98</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="Log-99"><a href="#Log-99"><span class="linenos"> 99</span></a>
+</span><span id="Log-100"><a href="#Log-100"><span class="linenos">100</span></a><span class="sd">    - &#39;filter&#39;: list of message templates to be logged.</span>
+</span><span id="Log-101"><a href="#Log-101"><span class="linenos">101</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Log-102"><a href="#Log-102"><span class="linenos">102</span></a>
+</span><span id="Log-103"><a href="#Log-103"><span class="linenos">103</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Log-104"><a href="#Log-104"><span class="linenos">104</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Log-105"><a href="#Log-105"><span class="linenos">105</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;filter&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_log</span><span class="p">)])</span>
+</span><span id="Log-106"><a href="#Log-106"><span class="linenos">106</span></a>
+</span><span id="Log-107"><a href="#Log-107"><span class="linenos">107</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_log</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Log-108"><a href="#Log-108"><span class="linenos">108</span></a>        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+</span><span id="Log-109"><a href="#Log-109"><span class="linenos">109</span></a>
+</span><span id="Log-110"><a href="#Log-110"><span class="linenos">110</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Log-111"><a href="#Log-111"><span class="linenos">111</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Log-112"><a href="#Log-112"><span class="linenos">112</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Log messages on stdout.</p>
+
+<p>The "filter" configuration key gets a list of message templates defining
+the messages that should be logged by the plugin instance.</p>
+
+<p>In the following example the first and third message match the given
+template and are logged by the instance "Test Log", while the second
+message does not match and is only logged by the test, but not by the
+Log instance:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Log&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                  <span class="s2">&quot;filter&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}}]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">,</span> <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="s2">&quot;Second Message&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="s2">&quot;Third Message&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>
+<span class="go">         &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>
+<span class="go">Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42.42, &#39;message&#39;: &#39;Second Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>
+<span class="go">Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>
+</code></pre>
+</div>
+
+<p>The "filter" key is required:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Log&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Log&quot;</span><span class="p">}},</span> <span class="p">[]))</span>
+<span class="go">data must contain [&#39;filter&#39;] properties</span>
+<span class="go">Configuration for &#39;Test Log&#39; is not valid.</span>
+</code></pre>
+</div>
+
+<p>The "filter" key has to contain a list of message templates, i.e.,
+JSON objects:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Log&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                  <span class="s2">&quot;filter&quot;</span><span class="p">:</span> <span class="p">[</span><span class="mi">42</span><span class="p">]}},</span> <span class="p">[]))</span>
+<span class="go">data.filter[0] must be object</span>
+<span class="go">Configuration for &#39;Test Log&#39; is not valid.</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Log.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;filter&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}}, &#39;required&#39;: [&#39;filter&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Log.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Log plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'filter': list of message templates to be logged.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Log.process_conf" class="classattr">
+                                        <input id="Log.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Log.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Log.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Log.process_conf-103"><a href="#Log.process_conf-103"><span class="linenos">103</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Log.process_conf-104"><a href="#Log.process_conf-104"><span class="linenos">104</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Log.process_conf-105"><a href="#Log.process_conf-105"><span class="linenos">105</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;Log&quot;</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;filter&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_log</span><span class="p">)])</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Log.run" class="classattr">
+                                        <input id="Log.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Log.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Log.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Log.run-110"><a href="#Log.run-110"><span class="linenos">110</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Log.run-111"><a href="#Log.run-111"><span class="linenos">111</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Log.run-112"><a href="#Log.run-112"><span class="linenos">112</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Log.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Log.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Log.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Log.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Init">
+                            <input id="Init-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Init</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Init-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Init"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Init-115"><a href="#Init-115"><span class="linenos">115</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Init</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Init-116"><a href="#Init-116"><span class="linenos">116</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send list of messages on startup and on demand.</span>
+</span><span id="Init-117"><a href="#Init-117"><span class="linenos">117</span></a>
+</span><span id="Init-118"><a href="#Init-118"><span class="linenos">118</span></a><span class="sd">    The &quot;messages&quot; configuration key gets a list of messages to be sent on</span>
+</span><span id="Init-119"><a href="#Init-119"><span class="linenos">119</span></a><span class="sd">    startup. The same list is sent in reaction to a message with</span>
+</span><span id="Init-120"><a href="#Init-120"><span class="linenos">120</span></a><span class="sd">    &quot;target&quot;: NAME and &quot;command&quot;: &quot;execute&quot;.</span>
+</span><span id="Init-121"><a href="#Init-121"><span class="linenos">121</span></a>
+</span><span id="Init-122"><a href="#Init-122"><span class="linenos">122</span></a><span class="sd">    In the example, the two configured messages are sent twice, once at</span>
+</span><span id="Init-123"><a href="#Init-123"><span class="linenos">123</span></a><span class="sd">    startup and a second time in reaction to the &quot;execute&quot; command sent by</span>
+</span><span id="Init-124"><a href="#Init-124"><span class="linenos">124</span></a><span class="sd">    the test:</span>
+</span><span id="Init-125"><a href="#Init-125"><span class="linenos">125</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Init-126"><a href="#Init-126"><span class="linenos">126</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Init-127"><a href="#Init-127"><span class="linenos">127</span></a><span class="sd">    ...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="Init-128"><a href="#Init-128"><span class="linenos">128</span></a><span class="sd">    ...                    &quot;messages&quot;: [{&quot;id&quot;: 42,</span>
+</span><span id="Init-129"><a href="#Init-129"><span class="linenos">129</span></a><span class="sd">    ...                                  &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="Init-130"><a href="#Init-130"><span class="linenos">130</span></a><span class="sd">    ...                                 {&quot;id&quot;: 42.42,</span>
+</span><span id="Init-131"><a href="#Init-131"><span class="linenos">131</span></a><span class="sd">    ...                                  &quot;content&quot;: &quot;Second Message&quot;}]}},</span>
+</span><span id="Init-132"><a href="#Init-132"><span class="linenos">132</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Init&quot;, &quot;command&quot;: &quot;execute&quot;}]))</span>
+</span><span id="Init-133"><a href="#Init-133"><span class="linenos">133</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Init-134"><a href="#Init-134"><span class="linenos">134</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Init-135"><a href="#Init-135"><span class="linenos">135</span></a><span class="sd">             &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+</span><span id="Init-136"><a href="#Init-136"><span class="linenos">136</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+</span><span id="Init-137"><a href="#Init-137"><span class="linenos">137</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>
+</span><span id="Init-138"><a href="#Init-138"><span class="linenos">138</span></a><span class="sd">                       {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>
+</span><span id="Init-139"><a href="#Init-139"><span class="linenos">139</span></a><span class="sd">                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>
+</span><span id="Init-140"><a href="#Init-140"><span class="linenos">140</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+</span><span id="Init-141"><a href="#Init-141"><span class="linenos">141</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="Init-142"><a href="#Init-142"><span class="linenos">142</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="Init-143"><a href="#Init-143"><span class="linenos">143</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="Init-144"><a href="#Init-144"><span class="linenos">144</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Init&#39;, &#39;command&#39;: &#39;execute&#39;}</span>
+</span><span id="Init-145"><a href="#Init-145"><span class="linenos">145</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="Init-146"><a href="#Init-146"><span class="linenos">146</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="Init-147"><a href="#Init-147"><span class="linenos">147</span></a>
+</span><span id="Init-148"><a href="#Init-148"><span class="linenos">148</span></a><span class="sd">    The &quot;messages&quot; key is required:</span>
+</span><span id="Init-149"><a href="#Init-149"><span class="linenos">149</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Init-150"><a href="#Init-150"><span class="linenos">150</span></a><span class="sd">    ...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;}}, []))</span>
+</span><span id="Init-151"><a href="#Init-151"><span class="linenos">151</span></a><span class="sd">    data must contain [&#39;messages&#39;] properties</span>
+</span><span id="Init-152"><a href="#Init-152"><span class="linenos">152</span></a><span class="sd">    Configuration for &#39;Test Init&#39; is not valid.</span>
+</span><span id="Init-153"><a href="#Init-153"><span class="linenos">153</span></a>
+</span><span id="Init-154"><a href="#Init-154"><span class="linenos">154</span></a><span class="sd">    The &quot;messages&quot; key has to contain a list of (partial) messages, i.e.,</span>
+</span><span id="Init-155"><a href="#Init-155"><span class="linenos">155</span></a><span class="sd">    JSON objects:</span>
+</span><span id="Init-156"><a href="#Init-156"><span class="linenos">156</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Init-157"><a href="#Init-157"><span class="linenos">157</span></a><span class="sd">    ...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,</span>
+</span><span id="Init-158"><a href="#Init-158"><span class="linenos">158</span></a><span class="sd">    ...                    &quot;messages&quot;: [42]}}, []))</span>
+</span><span id="Init-159"><a href="#Init-159"><span class="linenos">159</span></a><span class="sd">    data.messages[0] must be object</span>
+</span><span id="Init-160"><a href="#Init-160"><span class="linenos">160</span></a><span class="sd">    Configuration for &#39;Test Init&#39; is not valid.</span>
+</span><span id="Init-161"><a href="#Init-161"><span class="linenos">161</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Init-162"><a href="#Init-162"><span class="linenos">162</span></a>
+</span><span id="Init-163"><a href="#Init-163"><span class="linenos">163</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Init-164"><a href="#Init-164"><span class="linenos">164</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}}},</span>
+</span><span id="Init-165"><a href="#Init-165"><span class="linenos">165</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">],</span>
+</span><span id="Init-166"><a href="#Init-166"><span class="linenos">166</span></a>    <span class="p">}</span>
+</span><span id="Init-167"><a href="#Init-167"><span class="linenos">167</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Init plugin configuration.</span>
+</span><span id="Init-168"><a href="#Init-168"><span class="linenos">168</span></a>
+</span><span id="Init-169"><a href="#Init-169"><span class="linenos">169</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="Init-170"><a href="#Init-170"><span class="linenos">170</span></a>
+</span><span id="Init-171"><a href="#Init-171"><span class="linenos">171</span></a><span class="sd">    - &#39;messages&#39;: list of messages to be sent.</span>
+</span><span id="Init-172"><a href="#Init-172"><span class="linenos">172</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Init-173"><a href="#Init-173"><span class="linenos">173</span></a>
+</span><span id="Init-174"><a href="#Init-174"><span class="linenos">174</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Init-175"><a href="#Init-175"><span class="linenos">175</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Init-176"><a href="#Init-176"><span class="linenos">176</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Init-177"><a href="#Init-177"><span class="linenos">177</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Init-178"><a href="#Init-178"><span class="linenos">178</span></a>            <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+</span><span id="Init-179"><a href="#Init-179"><span class="linenos">179</span></a>            <span class="p">[</span>
+</span><span id="Init-180"><a href="#Init-180"><span class="linenos">180</span></a>                <span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span><span id="Init-181"><a href="#Init-181"><span class="linenos">181</span></a>                <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]</span>
+</span><span id="Init-182"><a href="#Init-182"><span class="linenos">182</span></a>            <span class="p">],</span>
+</span><span id="Init-183"><a href="#Init-183"><span class="linenos">183</span></a>            <span class="p">[</span>
+</span><span id="Init-184"><a href="#Init-184"><span class="linenos">184</span></a>                <span class="p">(</span>
+</span><span id="Init-185"><a href="#Init-185"><span class="linenos">185</span></a>                    <span class="p">[</span>
+</span><span id="Init-186"><a href="#Init-186"><span class="linenos">186</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Init-187"><a href="#Init-187"><span class="linenos">187</span></a>                            <span class="p">{</span>
+</span><span id="Init-188"><a href="#Init-188"><span class="linenos">188</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Init-189"><a href="#Init-189"><span class="linenos">189</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">},</span>
+</span><span id="Init-190"><a href="#Init-190"><span class="linenos">190</span></a>                            <span class="p">}</span>
+</span><span id="Init-191"><a href="#Init-191"><span class="linenos">191</span></a>                        <span class="p">)</span>
+</span><span id="Init-192"><a href="#Init-192"><span class="linenos">192</span></a>                    <span class="p">],</span>
+</span><span id="Init-193"><a href="#Init-193"><span class="linenos">193</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_execute</span><span class="p">,</span>
+</span><span id="Init-194"><a href="#Init-194"><span class="linenos">194</span></a>                <span class="p">)</span>
+</span><span id="Init-195"><a href="#Init-195"><span class="linenos">195</span></a>            <span class="p">],</span>
+</span><span id="Init-196"><a href="#Init-196"><span class="linenos">196</span></a>        <span class="p">)</span>
+</span><span id="Init-197"><a href="#Init-197"><span class="linenos">197</span></a>
+</span><span id="Init-198"><a href="#Init-198"><span class="linenos">198</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Init-199"><a href="#Init-199"><span class="linenos">199</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]:</span>
+</span><span id="Init-200"><a href="#Init-200"><span class="linenos">200</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="Init-201"><a href="#Init-201"><span class="linenos">201</span></a>            <span class="c1"># Give immediate reactions to messages opportunity to happen:</span>
+</span><span id="Init-202"><a href="#Init-202"><span class="linenos">202</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="Init-203"><a href="#Init-203"><span class="linenos">203</span></a>
+</span><span id="Init-204"><a href="#Init-204"><span class="linenos">204</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Init-205"><a href="#Init-205"><span class="linenos">205</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send configured messages on startup.&quot;&quot;&quot;</span>
+</span><span id="Init-206"><a href="#Init-206"><span class="linenos">206</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]:</span>
+</span><span id="Init-207"><a href="#Init-207"><span class="linenos">207</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send list of messages on startup and on demand.</p>
+
+<p>The "messages" configuration key gets a list of messages to be sent on
+startup. The same list is sent in reaction to a message with
+"target": NAME and "command": "execute".</p>
+
+<p>In the example, the two configured messages are sent twice, once at
+startup and a second time in reaction to the "execute" command sent by
+the test:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Init&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span>
+<span class="gp">... </span>                                 <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">},</span>
+<span class="gp">... </span>                                <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">,</span>
+<span class="gp">... </span>                                 <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Second Message&quot;</span><span class="p">}]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Init&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>
+<span class="go">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>
+<span class="go">                   {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>
+<span class="go">                    &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Init&#39;, &#39;command&#39;: &#39;execute&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>
+</code></pre>
+</div>
+
+<p>The "messages" key is required:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Init&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">}},</span> <span class="p">[]))</span>
+<span class="go">data must contain [&#39;messages&#39;] properties</span>
+<span class="go">Configuration for &#39;Test Init&#39; is not valid.</span>
+</code></pre>
+</div>
+
+<p>The "messages" key has to contain a list of (partial) messages, i.e.,
+JSON objects:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Init&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">[</span><span class="mi">42</span><span class="p">]}},</span> <span class="p">[]))</span>
+<span class="go">data.messages[0] must be object</span>
+<span class="go">Configuration for &#39;Test Init&#39; is not valid.</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Init.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<input id="Init.CONF_SCHEMA-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="Init.CONF_SCHEMA-view-value"></label><span class="default_value">{&#39;properties&#39;: {&#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}}, &#39;required&#39;: [&#39;messages&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Init.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Init plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'messages': list of messages to be sent.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Init.process_conf" class="classattr">
+                                        <input id="Init.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Init.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Init.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Init.process_conf-174"><a href="#Init.process_conf-174"><span class="linenos">174</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Init.process_conf-175"><a href="#Init.process_conf-175"><span class="linenos">175</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Init.process_conf-176"><a href="#Init.process_conf-176"><span class="linenos">176</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Init.process_conf-177"><a href="#Init.process_conf-177"><span class="linenos">177</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Init.process_conf-178"><a href="#Init.process_conf-178"><span class="linenos">178</span></a>            <span class="s2">&quot;Init&quot;</span><span class="p">,</span>
+</span><span id="Init.process_conf-179"><a href="#Init.process_conf-179"><span class="linenos">179</span></a>            <span class="p">[</span>
+</span><span id="Init.process_conf-180"><a href="#Init.process_conf-180"><span class="linenos">180</span></a>                <span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+</span><span id="Init.process_conf-181"><a href="#Init.process_conf-181"><span class="linenos">181</span></a>                <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]</span>
+</span><span id="Init.process_conf-182"><a href="#Init.process_conf-182"><span class="linenos">182</span></a>            <span class="p">],</span>
+</span><span id="Init.process_conf-183"><a href="#Init.process_conf-183"><span class="linenos">183</span></a>            <span class="p">[</span>
+</span><span id="Init.process_conf-184"><a href="#Init.process_conf-184"><span class="linenos">184</span></a>                <span class="p">(</span>
+</span><span id="Init.process_conf-185"><a href="#Init.process_conf-185"><span class="linenos">185</span></a>                    <span class="p">[</span>
+</span><span id="Init.process_conf-186"><a href="#Init.process_conf-186"><span class="linenos">186</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Init.process_conf-187"><a href="#Init.process_conf-187"><span class="linenos">187</span></a>                            <span class="p">{</span>
+</span><span id="Init.process_conf-188"><a href="#Init.process_conf-188"><span class="linenos">188</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Init.process_conf-189"><a href="#Init.process_conf-189"><span class="linenos">189</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">},</span>
+</span><span id="Init.process_conf-190"><a href="#Init.process_conf-190"><span class="linenos">190</span></a>                            <span class="p">}</span>
+</span><span id="Init.process_conf-191"><a href="#Init.process_conf-191"><span class="linenos">191</span></a>                        <span class="p">)</span>
+</span><span id="Init.process_conf-192"><a href="#Init.process_conf-192"><span class="linenos">192</span></a>                    <span class="p">],</span>
+</span><span id="Init.process_conf-193"><a href="#Init.process_conf-193"><span class="linenos">193</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_execute</span><span class="p">,</span>
+</span><span id="Init.process_conf-194"><a href="#Init.process_conf-194"><span class="linenos">194</span></a>                <span class="p">)</span>
+</span><span id="Init.process_conf-195"><a href="#Init.process_conf-195"><span class="linenos">195</span></a>            <span class="p">],</span>
+</span><span id="Init.process_conf-196"><a href="#Init.process_conf-196"><span class="linenos">196</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Init.run" class="classattr">
+                                        <input id="Init.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Init.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Init.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Init.run-204"><a href="#Init.run-204"><span class="linenos">204</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Init.run-205"><a href="#Init.run-205"><span class="linenos">205</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Send configured messages on startup.&quot;&quot;&quot;</span>
+</span><span id="Init.run-206"><a href="#Init.run-206"><span class="linenos">206</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">]:</span>
+</span><span id="Init.run-207"><a href="#Init.run-207"><span class="linenos">207</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send configured messages on startup.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Init.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Init.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Init.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Init.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Execute">
+                            <input id="Execute-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Execute</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Execute-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Execute"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Execute-210"><a href="#Execute-210"><span class="linenos">210</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Execute</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Execute-211"><a href="#Execute-211"><span class="linenos">211</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send configurable list of messages on demand.</span>
+</span><span id="Execute-212"><a href="#Execute-212"><span class="linenos">212</span></a>
+</span><span id="Execute-213"><a href="#Execute-213"><span class="linenos">213</span></a><span class="sd">    An Execute plugin instance receives two kinds of commands.</span>
+</span><span id="Execute-214"><a href="#Execute-214"><span class="linenos">214</span></a><span class="sd">    The &quot;set messages&quot; command has a &quot;messages&quot; key with a list of (partial)</span>
+</span><span id="Execute-215"><a href="#Execute-215"><span class="linenos">215</span></a><span class="sd">    messages, which are sent by the Execute instance in reaction to an</span>
+</span><span id="Execute-216"><a href="#Execute-216"><span class="linenos">216</span></a><span class="sd">    &quot;execute&quot; command.</span>
+</span><span id="Execute-217"><a href="#Execute-217"><span class="linenos">217</span></a>
+</span><span id="Execute-218"><a href="#Execute-218"><span class="linenos">218</span></a><span class="sd">    In the example, the first command sent by the test sets two messages,</span>
+</span><span id="Execute-219"><a href="#Execute-219"><span class="linenos">219</span></a><span class="sd">    which are then sent in reaction to the second command sent by the test:</span>
+</span><span id="Execute-220"><a href="#Execute-220"><span class="linenos">220</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Execute-221"><a href="#Execute-221"><span class="linenos">221</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Execute-222"><a href="#Execute-222"><span class="linenos">222</span></a><span class="sd">    ...     {&quot;Test Execute&quot;: {&quot;plugin&quot;: &quot;Execute&quot;}},</span>
+</span><span id="Execute-223"><a href="#Execute-223"><span class="linenos">223</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Execute&quot;, &quot;command&quot;: &quot;set messages&quot;,</span>
+</span><span id="Execute-224"><a href="#Execute-224"><span class="linenos">224</span></a><span class="sd">    ...       &quot;messages&quot;: [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;},</span>
+</span><span id="Execute-225"><a href="#Execute-225"><span class="linenos">225</span></a><span class="sd">    ...                    {&quot;id&quot;: 42.42, &quot;content&quot;: &quot;Second Message&quot;}]},</span>
+</span><span id="Execute-226"><a href="#Execute-226"><span class="linenos">226</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Execute&quot;, &quot;command&quot;: &quot;execute&quot;}]))</span>
+</span><span id="Execute-227"><a href="#Execute-227"><span class="linenos">227</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Execute-228"><a href="#Execute-228"><span class="linenos">228</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Execute-229"><a href="#Execute-229"><span class="linenos">229</span></a><span class="sd">             &#39;client&#39;: &#39;Test Execute&#39;, &#39;plugin&#39;: &#39;Execute&#39;,</span>
+</span><span id="Execute-230"><a href="#Execute-230"><span class="linenos">230</span></a><span class="sd">             &#39;sends&#39;: [{}],</span>
+</span><span id="Execute-231"><a href="#Execute-231"><span class="linenos">231</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>
+</span><span id="Execute-232"><a href="#Execute-232"><span class="linenos">232</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},</span>
+</span><span id="Execute-233"><a href="#Execute-233"><span class="linenos">233</span></a><span class="sd">                           &#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+</span><span id="Execute-234"><a href="#Execute-234"><span class="linenos">234</span></a><span class="sd">                                        &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},</span>
+</span><span id="Execute-235"><a href="#Execute-235"><span class="linenos">235</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>
+</span><span id="Execute-236"><a href="#Execute-236"><span class="linenos">236</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+</span><span id="Execute-237"><a href="#Execute-237"><span class="linenos">237</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>
+</span><span id="Execute-238"><a href="#Execute-238"><span class="linenos">238</span></a><span class="sd">             &#39;command&#39;: &#39;set messages&#39;,</span>
+</span><span id="Execute-239"><a href="#Execute-239"><span class="linenos">239</span></a><span class="sd">             &#39;messages&#39;: [{&#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;},</span>
+</span><span id="Execute-240"><a href="#Execute-240"><span class="linenos">240</span></a><span class="sd">                          {&#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}]}</span>
+</span><span id="Execute-241"><a href="#Execute-241"><span class="linenos">241</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>
+</span><span id="Execute-242"><a href="#Execute-242"><span class="linenos">242</span></a><span class="sd">             &#39;command&#39;: &#39;execute&#39;}</span>
+</span><span id="Execute-243"><a href="#Execute-243"><span class="linenos">243</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42,</span>
+</span><span id="Execute-244"><a href="#Execute-244"><span class="linenos">244</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;}</span>
+</span><span id="Execute-245"><a href="#Execute-245"><span class="linenos">245</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42.42,</span>
+</span><span id="Execute-246"><a href="#Execute-246"><span class="linenos">246</span></a><span class="sd">             &#39;content&#39;: &#39;Second Message&#39;}</span>
+</span><span id="Execute-247"><a href="#Execute-247"><span class="linenos">247</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Execute-248"><a href="#Execute-248"><span class="linenos">248</span></a>
+</span><span id="Execute-249"><a href="#Execute-249"><span class="linenos">249</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="Execute-250"><a href="#Execute-250"><span class="linenos">250</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Execute plugin configuration.</span>
+</span><span id="Execute-251"><a href="#Execute-251"><span class="linenos">251</span></a>
+</span><span id="Execute-252"><a href="#Execute-252"><span class="linenos">252</span></a><span class="sd">    There are no required or optional configuration keys.</span>
+</span><span id="Execute-253"><a href="#Execute-253"><span class="linenos">253</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Execute-254"><a href="#Execute-254"><span class="linenos">254</span></a>
+</span><span id="Execute-255"><a href="#Execute-255"><span class="linenos">255</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Execute-256"><a href="#Execute-256"><span class="linenos">256</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Execute-257"><a href="#Execute-257"><span class="linenos">257</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Message</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="Execute-258"><a href="#Execute-258"><span class="linenos">258</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Execute-259"><a href="#Execute-259"><span class="linenos">259</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Execute-260"><a href="#Execute-260"><span class="linenos">260</span></a>            <span class="s2">&quot;Execute&quot;</span><span class="p">,</span>
+</span><span id="Execute-261"><a href="#Execute-261"><span class="linenos">261</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">()],</span>
+</span><span id="Execute-262"><a href="#Execute-262"><span class="linenos">262</span></a>            <span class="p">[</span>
+</span><span id="Execute-263"><a href="#Execute-263"><span class="linenos">263</span></a>                <span class="p">(</span>
+</span><span id="Execute-264"><a href="#Execute-264"><span class="linenos">264</span></a>                    <span class="p">[</span>
+</span><span id="Execute-265"><a href="#Execute-265"><span class="linenos">265</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Execute-266"><a href="#Execute-266"><span class="linenos">266</span></a>                            <span class="p">{</span>
+</span><span id="Execute-267"><a href="#Execute-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Execute-268"><a href="#Execute-268"><span class="linenos">268</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set messages&quot;</span><span class="p">},</span>
+</span><span id="Execute-269"><a href="#Execute-269"><span class="linenos">269</span></a>                                <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Execute-270"><a href="#Execute-270"><span class="linenos">270</span></a>                                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="Execute-271"><a href="#Execute-271"><span class="linenos">271</span></a>                                    <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="Execute-272"><a href="#Execute-272"><span class="linenos">272</span></a>                                <span class="p">},</span>
+</span><span id="Execute-273"><a href="#Execute-273"><span class="linenos">273</span></a>                            <span class="p">}</span>
+</span><span id="Execute-274"><a href="#Execute-274"><span class="linenos">274</span></a>                        <span class="p">)</span>
+</span><span id="Execute-275"><a href="#Execute-275"><span class="linenos">275</span></a>                    <span class="p">],</span>
+</span><span id="Execute-276"><a href="#Execute-276"><span class="linenos">276</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_messages</span><span class="p">,</span>
+</span><span id="Execute-277"><a href="#Execute-277"><span class="linenos">277</span></a>                <span class="p">),</span>
+</span><span id="Execute-278"><a href="#Execute-278"><span class="linenos">278</span></a>                <span class="p">(</span>
+</span><span id="Execute-279"><a href="#Execute-279"><span class="linenos">279</span></a>                    <span class="p">[</span>
+</span><span id="Execute-280"><a href="#Execute-280"><span class="linenos">280</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Execute-281"><a href="#Execute-281"><span class="linenos">281</span></a>                            <span class="p">{</span>
+</span><span id="Execute-282"><a href="#Execute-282"><span class="linenos">282</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Execute-283"><a href="#Execute-283"><span class="linenos">283</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">},</span>
+</span><span id="Execute-284"><a href="#Execute-284"><span class="linenos">284</span></a>                            <span class="p">}</span>
+</span><span id="Execute-285"><a href="#Execute-285"><span class="linenos">285</span></a>                        <span class="p">)</span>
+</span><span id="Execute-286"><a href="#Execute-286"><span class="linenos">286</span></a>                    <span class="p">],</span>
+</span><span id="Execute-287"><a href="#Execute-287"><span class="linenos">287</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_execute</span><span class="p">,</span>
+</span><span id="Execute-288"><a href="#Execute-288"><span class="linenos">288</span></a>                <span class="p">),</span>
+</span><span id="Execute-289"><a href="#Execute-289"><span class="linenos">289</span></a>            <span class="p">],</span>
+</span><span id="Execute-290"><a href="#Execute-290"><span class="linenos">290</span></a>        <span class="p">)</span>
+</span><span id="Execute-291"><a href="#Execute-291"><span class="linenos">291</span></a>
+</span><span id="Execute-292"><a href="#Execute-292"><span class="linenos">292</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_set_messages</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Execute-293"><a href="#Execute-293"><span class="linenos">293</span></a>        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">],</span> <span class="nb">list</span><span class="p">)</span>
+</span><span id="Execute-294"><a href="#Execute-294"><span class="linenos">294</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">messages</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;messages&quot;</span><span class="p">])</span>
+</span><span id="Execute-295"><a href="#Execute-295"><span class="linenos">295</span></a>
+</span><span id="Execute-296"><a href="#Execute-296"><span class="linenos">296</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Execute-297"><a href="#Execute-297"><span class="linenos">297</span></a>        <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
+</span><span id="Execute-298"><a href="#Execute-298"><span class="linenos">298</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span>
+</span><span id="Execute-299"><a href="#Execute-299"><span class="linenos">299</span></a>            <span class="c1"># Give immediate reactions to messages opportunity to happen:</span>
+</span><span id="Execute-300"><a href="#Execute-300"><span class="linenos">300</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+</span><span id="Execute-301"><a href="#Execute-301"><span class="linenos">301</span></a>
+</span><span id="Execute-302"><a href="#Execute-302"><span class="linenos">302</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Execute-303"><a href="#Execute-303"><span class="linenos">303</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Execute-304"><a href="#Execute-304"><span class="linenos">304</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send configurable list of messages on demand.</p>
+
+<p>An Execute plugin instance receives two kinds of commands.
+The "set messages" command has a "messages" key with a list of (partial)
+messages, which are sent by the Execute instance in reaction to an
+"execute" command.</p>
+
+<p>In the example, the first command sent by the test sets two messages,
+which are then sent in reaction to the second command sent by the test:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Execute&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Execute&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Execute&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;set messages&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">},</span>
+<span class="gp">... </span>                   <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mf">42.42</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Second Message&quot;</span><span class="p">}]},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Execute&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Execute&#39;, &#39;plugin&#39;: &#39;Execute&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},</span>
+<span class="go">                       &#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,</span>
+<span class="go">                                    &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},</span>
+<span class="go">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;set messages&#39;,</span>
+<span class="go">         &#39;messages&#39;: [{&#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;},</span>
+<span class="go">                      {&#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;execute&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42.42,</span>
+<span class="go">         &#39;content&#39;: &#39;Second Message&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Execute.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">True</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Execute.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Execute plugin configuration.</p>
+
+<p>There are no required or optional configuration keys.</p>
+</div>
+
+
+                            </div>
+                            <div id="Execute.process_conf" class="classattr">
+                                        <input id="Execute.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Execute.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Execute.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Execute.process_conf-255"><a href="#Execute.process_conf-255"><span class="linenos">255</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Execute.process_conf-256"><a href="#Execute.process_conf-256"><span class="linenos">256</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Execute.process_conf-257"><a href="#Execute.process_conf-257"><span class="linenos">257</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Message</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="Execute.process_conf-258"><a href="#Execute.process_conf-258"><span class="linenos">258</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Execute.process_conf-259"><a href="#Execute.process_conf-259"><span class="linenos">259</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Execute.process_conf-260"><a href="#Execute.process_conf-260"><span class="linenos">260</span></a>            <span class="s2">&quot;Execute&quot;</span><span class="p">,</span>
+</span><span id="Execute.process_conf-261"><a href="#Execute.process_conf-261"><span class="linenos">261</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">()],</span>
+</span><span id="Execute.process_conf-262"><a href="#Execute.process_conf-262"><span class="linenos">262</span></a>            <span class="p">[</span>
+</span><span id="Execute.process_conf-263"><a href="#Execute.process_conf-263"><span class="linenos">263</span></a>                <span class="p">(</span>
+</span><span id="Execute.process_conf-264"><a href="#Execute.process_conf-264"><span class="linenos">264</span></a>                    <span class="p">[</span>
+</span><span id="Execute.process_conf-265"><a href="#Execute.process_conf-265"><span class="linenos">265</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Execute.process_conf-266"><a href="#Execute.process_conf-266"><span class="linenos">266</span></a>                            <span class="p">{</span>
+</span><span id="Execute.process_conf-267"><a href="#Execute.process_conf-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Execute.process_conf-268"><a href="#Execute.process_conf-268"><span class="linenos">268</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;set messages&quot;</span><span class="p">},</span>
+</span><span id="Execute.process_conf-269"><a href="#Execute.process_conf-269"><span class="linenos">269</span></a>                                <span class="s2">&quot;messages&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Execute.process_conf-270"><a href="#Execute.process_conf-270"><span class="linenos">270</span></a>                                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="Execute.process_conf-271"><a href="#Execute.process_conf-271"><span class="linenos">271</span></a>                                    <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="Execute.process_conf-272"><a href="#Execute.process_conf-272"><span class="linenos">272</span></a>                                <span class="p">},</span>
+</span><span id="Execute.process_conf-273"><a href="#Execute.process_conf-273"><span class="linenos">273</span></a>                            <span class="p">}</span>
+</span><span id="Execute.process_conf-274"><a href="#Execute.process_conf-274"><span class="linenos">274</span></a>                        <span class="p">)</span>
+</span><span id="Execute.process_conf-275"><a href="#Execute.process_conf-275"><span class="linenos">275</span></a>                    <span class="p">],</span>
+</span><span id="Execute.process_conf-276"><a href="#Execute.process_conf-276"><span class="linenos">276</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_set_messages</span><span class="p">,</span>
+</span><span id="Execute.process_conf-277"><a href="#Execute.process_conf-277"><span class="linenos">277</span></a>                <span class="p">),</span>
+</span><span id="Execute.process_conf-278"><a href="#Execute.process_conf-278"><span class="linenos">278</span></a>                <span class="p">(</span>
+</span><span id="Execute.process_conf-279"><a href="#Execute.process_conf-279"><span class="linenos">279</span></a>                    <span class="p">[</span>
+</span><span id="Execute.process_conf-280"><a href="#Execute.process_conf-280"><span class="linenos">280</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Execute.process_conf-281"><a href="#Execute.process_conf-281"><span class="linenos">281</span></a>                            <span class="p">{</span>
+</span><span id="Execute.process_conf-282"><a href="#Execute.process_conf-282"><span class="linenos">282</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Execute.process_conf-283"><a href="#Execute.process_conf-283"><span class="linenos">283</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;execute&quot;</span><span class="p">},</span>
+</span><span id="Execute.process_conf-284"><a href="#Execute.process_conf-284"><span class="linenos">284</span></a>                            <span class="p">}</span>
+</span><span id="Execute.process_conf-285"><a href="#Execute.process_conf-285"><span class="linenos">285</span></a>                        <span class="p">)</span>
+</span><span id="Execute.process_conf-286"><a href="#Execute.process_conf-286"><span class="linenos">286</span></a>                    <span class="p">],</span>
+</span><span id="Execute.process_conf-287"><a href="#Execute.process_conf-287"><span class="linenos">287</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_execute</span><span class="p">,</span>
+</span><span id="Execute.process_conf-288"><a href="#Execute.process_conf-288"><span class="linenos">288</span></a>                <span class="p">),</span>
+</span><span id="Execute.process_conf-289"><a href="#Execute.process_conf-289"><span class="linenos">289</span></a>            <span class="p">],</span>
+</span><span id="Execute.process_conf-290"><a href="#Execute.process_conf-290"><span class="linenos">290</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Execute.run" class="classattr">
+                                        <input id="Execute.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Execute.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Execute.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Execute.run-302"><a href="#Execute.run-302"><span class="linenos">302</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Execute.run-303"><a href="#Execute.run-303"><span class="linenos">303</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Execute.run-304"><a href="#Execute.run-304"><span class="linenos">304</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Execute.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Execute.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Execute.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Execute.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Alias">
+                            <input id="Alias-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Alias</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Alias-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Alias"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Alias-307"><a href="#Alias-307"><span class="linenos">307</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Alias</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Alias-308"><a href="#Alias-308"><span class="linenos">308</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Translate messages to an alias.</span>
+</span><span id="Alias-309"><a href="#Alias-309"><span class="linenos">309</span></a>
+</span><span id="Alias-310"><a href="#Alias-310"><span class="linenos">310</span></a><span class="sd">    The &quot;from&quot; configuration key gets a message template and the</span>
+</span><span id="Alias-311"><a href="#Alias-311"><span class="linenos">311</span></a><span class="sd">    configuration key &quot;to&quot; a (partial) message. The &quot;translate&quot;</span>
+</span><span id="Alias-312"><a href="#Alias-312"><span class="linenos">312</span></a><span class="sd">    configuration key contains pairs of message keys, where the &quot;from&quot;</span>
+</span><span id="Alias-313"><a href="#Alias-313"><span class="linenos">313</span></a><span class="sd">    message key is translated to the &quot;to&quot; message key if present in the</span>
+</span><span id="Alias-314"><a href="#Alias-314"><span class="linenos">314</span></a><span class="sd">    message.</span>
+</span><span id="Alias-315"><a href="#Alias-315"><span class="linenos">315</span></a>
+</span><span id="Alias-316"><a href="#Alias-316"><span class="linenos">316</span></a><span class="sd">    All messages matching the &quot;from&quot; template are received by the Alias</span>
+</span><span id="Alias-317"><a href="#Alias-317"><span class="linenos">317</span></a><span class="sd">    instance and a message translated by adding the keys and values of the</span>
+</span><span id="Alias-318"><a href="#Alias-318"><span class="linenos">318</span></a><span class="sd">    &quot;to&quot; message and the translated key-value pairs according to</span>
+</span><span id="Alias-319"><a href="#Alias-319"><span class="linenos">319</span></a><span class="sd">    &quot;translate&quot; is sent. Keys that are not &quot;sender&quot; and not modified by</span>
+</span><span id="Alias-320"><a href="#Alias-320"><span class="linenos">320</span></a><span class="sd">    &quot;to&quot; or &quot;translate&quot; are retained.</span>
+</span><span id="Alias-321"><a href="#Alias-321"><span class="linenos">321</span></a>
+</span><span id="Alias-322"><a href="#Alias-322"><span class="linenos">322</span></a><span class="sd">    In the example, the two messages sent by the test are translated by the</span>
+</span><span id="Alias-323"><a href="#Alias-323"><span class="linenos">323</span></a><span class="sd">    Alias instance and the translated messages are sent by it preserving</span>
+</span><span id="Alias-324"><a href="#Alias-324"><span class="linenos">324</span></a><span class="sd">    the &quot;content&quot; keys:</span>
+</span><span id="Alias-325"><a href="#Alias-325"><span class="linenos">325</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Alias-326"><a href="#Alias-326"><span class="linenos">326</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Alias-327"><a href="#Alias-327"><span class="linenos">327</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="Alias-328"><a href="#Alias-328"><span class="linenos">328</span></a><span class="sd">    ...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="Alias-329"><a href="#Alias-329"><span class="linenos">329</span></a><span class="sd">    ...                     &quot;to&quot;: {&quot;id&quot;: &quot;translated&quot;},</span>
+</span><span id="Alias-330"><a href="#Alias-330"><span class="linenos">330</span></a><span class="sd">    ...                     &quot;translate&quot;: [{&#39;from&#39;: &quot;old&quot;, &quot;to&quot;: &quot;new&quot;}]}},</span>
+</span><span id="Alias-331"><a href="#Alias-331"><span class="linenos">331</span></a><span class="sd">    ...     [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;, &quot;old&quot;: &quot;content&quot;},</span>
+</span><span id="Alias-332"><a href="#Alias-332"><span class="linenos">332</span></a><span class="sd">    ...      {&quot;id&quot;: 42, &quot;content&quot;: &quot;Second Message&quot;, &quot;old&quot;: &quot;content&quot;}]))</span>
+</span><span id="Alias-333"><a href="#Alias-333"><span class="linenos">333</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Alias-334"><a href="#Alias-334"><span class="linenos">334</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Alias-335"><a href="#Alias-335"><span class="linenos">335</span></a><span class="sd">             &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+</span><span id="Alias-336"><a href="#Alias-336"><span class="linenos">336</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>
+</span><span id="Alias-337"><a href="#Alias-337"><span class="linenos">337</span></a><span class="sd">             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="Alias-338"><a href="#Alias-338"><span class="linenos">338</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+</span><span id="Alias-339"><a href="#Alias-339"><span class="linenos">339</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-340"><a href="#Alias-340"><span class="linenos">340</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+</span><span id="Alias-341"><a href="#Alias-341"><span class="linenos">341</span></a><span class="sd">             &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-342"><a href="#Alias-342"><span class="linenos">342</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+</span><span id="Alias-343"><a href="#Alias-343"><span class="linenos">343</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-344"><a href="#Alias-344"><span class="linenos">344</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+</span><span id="Alias-345"><a href="#Alias-345"><span class="linenos">345</span></a><span class="sd">             &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-346"><a href="#Alias-346"><span class="linenos">346</span></a>
+</span><span id="Alias-347"><a href="#Alias-347"><span class="linenos">347</span></a><span class="sd">    An Alias instance can also translate to a list of messages instead of</span>
+</span><span id="Alias-348"><a href="#Alias-348"><span class="linenos">348</span></a><span class="sd">    a single message:</span>
+</span><span id="Alias-349"><a href="#Alias-349"><span class="linenos">349</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Alias-350"><a href="#Alias-350"><span class="linenos">350</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="Alias-351"><a href="#Alias-351"><span class="linenos">351</span></a><span class="sd">    ...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="Alias-352"><a href="#Alias-352"><span class="linenos">352</span></a><span class="sd">    ...                     &quot;to&quot;: [{&quot;id&quot;: &quot;first&quot;}, {&quot;id&quot;: &quot;second&quot;}],</span>
+</span><span id="Alias-353"><a href="#Alias-353"><span class="linenos">353</span></a><span class="sd">    ...                     &quot;translate&quot;: [{&#39;from&#39;: &quot;old&quot;, &quot;to&quot;: &quot;new&quot;}]}},</span>
+</span><span id="Alias-354"><a href="#Alias-354"><span class="linenos">354</span></a><span class="sd">    ...     [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;, &quot;old&quot;: &quot;content&quot;}]))</span>
+</span><span id="Alias-355"><a href="#Alias-355"><span class="linenos">355</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Alias-356"><a href="#Alias-356"><span class="linenos">356</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Alias-357"><a href="#Alias-357"><span class="linenos">357</span></a><span class="sd">             &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+</span><span id="Alias-358"><a href="#Alias-358"><span class="linenos">358</span></a><span class="sd">             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;first&#39;}},</span>
+</span><span id="Alias-359"><a href="#Alias-359"><span class="linenos">359</span></a><span class="sd">                       {&#39;id&#39;: {&#39;const&#39;: &#39;second&#39;}}],</span>
+</span><span id="Alias-360"><a href="#Alias-360"><span class="linenos">360</span></a><span class="sd">             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+</span><span id="Alias-361"><a href="#Alias-361"><span class="linenos">361</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+</span><span id="Alias-362"><a href="#Alias-362"><span class="linenos">362</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-363"><a href="#Alias-363"><span class="linenos">363</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;first&#39;,</span>
+</span><span id="Alias-364"><a href="#Alias-364"><span class="linenos">364</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-365"><a href="#Alias-365"><span class="linenos">365</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;second&#39;,</span>
+</span><span id="Alias-366"><a href="#Alias-366"><span class="linenos">366</span></a><span class="sd">             &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</span><span id="Alias-367"><a href="#Alias-367"><span class="linenos">367</span></a>
+</span><span id="Alias-368"><a href="#Alias-368"><span class="linenos">368</span></a><span class="sd">    The &quot;from&quot; key is required:</span>
+</span><span id="Alias-369"><a href="#Alias-369"><span class="linenos">369</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Alias-370"><a href="#Alias-370"><span class="linenos">370</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;}}, []))</span>
+</span><span id="Alias-371"><a href="#Alias-371"><span class="linenos">371</span></a><span class="sd">    data must contain [&#39;from&#39;] properties</span>
+</span><span id="Alias-372"><a href="#Alias-372"><span class="linenos">372</span></a><span class="sd">    Configuration for &#39;Test Alias&#39; is not valid.</span>
+</span><span id="Alias-373"><a href="#Alias-373"><span class="linenos">373</span></a>
+</span><span id="Alias-374"><a href="#Alias-374"><span class="linenos">374</span></a><span class="sd">    The &quot;from&quot; key has to contain a message template and the &quot;to&quot; key a</span>
+</span><span id="Alias-375"><a href="#Alias-375"><span class="linenos">375</span></a><span class="sd">    (partial) message, i.e., both have to be JSON objects:</span>
+</span><span id="Alias-376"><a href="#Alias-376"><span class="linenos">376</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Alias-377"><a href="#Alias-377"><span class="linenos">377</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="Alias-378"><a href="#Alias-378"><span class="linenos">378</span></a><span class="sd">    ...                     &quot;from&quot;: 42,</span>
+</span><span id="Alias-379"><a href="#Alias-379"><span class="linenos">379</span></a><span class="sd">    ...                     &quot;to&quot;: 42}}, []))</span>
+</span><span id="Alias-380"><a href="#Alias-380"><span class="linenos">380</span></a><span class="sd">    data.from must be object</span>
+</span><span id="Alias-381"><a href="#Alias-381"><span class="linenos">381</span></a><span class="sd">    Configuration for &#39;Test Alias&#39; is not valid.</span>
+</span><span id="Alias-382"><a href="#Alias-382"><span class="linenos">382</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Alias-383"><a href="#Alias-383"><span class="linenos">383</span></a><span class="sd">    ...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,</span>
+</span><span id="Alias-384"><a href="#Alias-384"><span class="linenos">384</span></a><span class="sd">    ...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},</span>
+</span><span id="Alias-385"><a href="#Alias-385"><span class="linenos">385</span></a><span class="sd">    ...                     &quot;to&quot;: 42}}, []))</span>
+</span><span id="Alias-386"><a href="#Alias-386"><span class="linenos">386</span></a><span class="sd">    data.to cannot be validated by any definition</span>
+</span><span id="Alias-387"><a href="#Alias-387"><span class="linenos">387</span></a><span class="sd">    Configuration for &#39;Test Alias&#39; is not valid.</span>
+</span><span id="Alias-388"><a href="#Alias-388"><span class="linenos">388</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Alias-389"><a href="#Alias-389"><span class="linenos">389</span></a>
+</span><span id="Alias-390"><a href="#Alias-390"><span class="linenos">390</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Alias-391"><a href="#Alias-391"><span class="linenos">391</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Alias-392"><a href="#Alias-392"><span class="linenos">392</span></a>            <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="Alias-393"><a href="#Alias-393"><span class="linenos">393</span></a>            <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Alias-394"><a href="#Alias-394"><span class="linenos">394</span></a>                <span class="s2">&quot;anyOf&quot;</span><span class="p">:</span> <span class="p">[</span>
+</span><span id="Alias-395"><a href="#Alias-395"><span class="linenos">395</span></a>                    <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="Alias-396"><a href="#Alias-396"><span class="linenos">396</span></a>                    <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span> <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}},</span>
+</span><span id="Alias-397"><a href="#Alias-397"><span class="linenos">397</span></a>                <span class="p">]</span>
+</span><span id="Alias-398"><a href="#Alias-398"><span class="linenos">398</span></a>            <span class="p">},</span>
+</span><span id="Alias-399"><a href="#Alias-399"><span class="linenos">399</span></a>            <span class="s2">&quot;translate&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Alias-400"><a href="#Alias-400"><span class="linenos">400</span></a>                <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;array&quot;</span><span class="p">,</span>
+</span><span id="Alias-401"><a href="#Alias-401"><span class="linenos">401</span></a>                <span class="s2">&quot;items&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Alias-402"><a href="#Alias-402"><span class="linenos">402</span></a>                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">,</span>
+</span><span id="Alias-403"><a href="#Alias-403"><span class="linenos">403</span></a>                    <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Alias-404"><a href="#Alias-404"><span class="linenos">404</span></a>                        <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="Alias-405"><a href="#Alias-405"><span class="linenos">405</span></a>                        <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="Alias-406"><a href="#Alias-406"><span class="linenos">406</span></a>                    <span class="p">},</span>
+</span><span id="Alias-407"><a href="#Alias-407"><span class="linenos">407</span></a>                <span class="p">},</span>
+</span><span id="Alias-408"><a href="#Alias-408"><span class="linenos">408</span></a>            <span class="p">},</span>
+</span><span id="Alias-409"><a href="#Alias-409"><span class="linenos">409</span></a>        <span class="p">},</span>
+</span><span id="Alias-410"><a href="#Alias-410"><span class="linenos">410</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">],</span>
+</span><span id="Alias-411"><a href="#Alias-411"><span class="linenos">411</span></a>    <span class="p">}</span>
+</span><span id="Alias-412"><a href="#Alias-412"><span class="linenos">412</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Alias plugin configuration.</span>
+</span><span id="Alias-413"><a href="#Alias-413"><span class="linenos">413</span></a>
+</span><span id="Alias-414"><a href="#Alias-414"><span class="linenos">414</span></a><span class="sd">    Required configuration keys:</span>
+</span><span id="Alias-415"><a href="#Alias-415"><span class="linenos">415</span></a>
+</span><span id="Alias-416"><a href="#Alias-416"><span class="linenos">416</span></a><span class="sd">    - &#39;from&#39;: template of messages to be translated.</span>
+</span><span id="Alias-417"><a href="#Alias-417"><span class="linenos">417</span></a>
+</span><span id="Alias-418"><a href="#Alias-418"><span class="linenos">418</span></a><span class="sd">    Optional configuration keys:</span>
+</span><span id="Alias-419"><a href="#Alias-419"><span class="linenos">419</span></a>
+</span><span id="Alias-420"><a href="#Alias-420"><span class="linenos">420</span></a><span class="sd">    - &#39;to&#39;: translated message(s) to be sent.</span>
+</span><span id="Alias-421"><a href="#Alias-421"><span class="linenos">421</span></a><span class="sd">    - &#39;translate&#39;: array of pairs of keys to be translated.</span>
+</span><span id="Alias-422"><a href="#Alias-422"><span class="linenos">422</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Alias-423"><a href="#Alias-423"><span class="linenos">423</span></a>
+</span><span id="Alias-424"><a href="#Alias-424"><span class="linenos">424</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Alias-425"><a href="#Alias-425"><span class="linenos">425</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Alias-426"><a href="#Alias-426"><span class="linenos">426</span></a>        <span class="n">sends</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="Alias-427"><a href="#Alias-427"><span class="linenos">427</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="Alias-428"><a href="#Alias-428"><span class="linenos">428</span></a>        <span class="k">if</span> <span class="s2">&quot;to&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+</span><span id="Alias-429"><a href="#Alias-429"><span class="linenos">429</span></a>            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">],</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="Alias-430"><a href="#Alias-430"><span class="linenos">430</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]</span>
+</span><span id="Alias-431"><a href="#Alias-431"><span class="linenos">431</span></a>                <span class="k">for</span> <span class="n">to</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]:</span>
+</span><span id="Alias-432"><a href="#Alias-432"><span class="linenos">432</span></a>                    <span class="n">sends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="n">to</span><span class="p">))</span>
+</span><span id="Alias-433"><a href="#Alias-433"><span class="linenos">433</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="Alias-434"><a href="#Alias-434"><span class="linenos">434</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]]</span>
+</span><span id="Alias-435"><a href="#Alias-435"><span class="linenos">435</span></a>                <span class="n">sends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]))</span>
+</span><span id="Alias-436"><a href="#Alias-436"><span class="linenos">436</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="Alias-437"><a href="#Alias-437"><span class="linenos">437</span></a>        <span class="k">if</span> <span class="s2">&quot;translate&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+</span><span id="Alias-438"><a href="#Alias-438"><span class="linenos">438</span></a>            <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;translate&quot;</span><span class="p">]:</span>
+</span><span id="Alias-439"><a href="#Alias-439"><span class="linenos">439</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">[</span><span class="n">pair</span><span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">pair</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]</span>
+</span><span id="Alias-440"><a href="#Alias-440"><span class="linenos">440</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Alias-441"><a href="#Alias-441"><span class="linenos">441</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span> <span class="n">sends</span><span class="p">,</span> <span class="p">[([</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">]],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_alias</span><span class="p">)]</span>
+</span><span id="Alias-442"><a href="#Alias-442"><span class="linenos">442</span></a>        <span class="p">)</span>
+</span><span id="Alias-443"><a href="#Alias-443"><span class="linenos">443</span></a>
+</span><span id="Alias-444"><a href="#Alias-444"><span class="linenos">444</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_alias</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Alias-445"><a href="#Alias-445"><span class="linenos">445</span></a>        <span class="c1"># Prevent endless loop:</span>
+</span><span id="Alias-446"><a href="#Alias-446"><span class="linenos">446</span></a>        <span class="k">if</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">:</span>
+</span><span id="Alias-447"><a href="#Alias-447"><span class="linenos">447</span></a>            <span class="k">for</span> <span class="n">to</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_to</span><span class="p">:</span>
+</span><span id="Alias-448"><a href="#Alias-448"><span class="linenos">448</span></a>                <span class="n">alias_message</span> <span class="o">=</span> <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
+</span><span id="Alias-449"><a href="#Alias-449"><span class="linenos">449</span></a>                <span class="n">alias_message</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">to</span><span class="p">)</span>
+</span><span id="Alias-450"><a href="#Alias-450"><span class="linenos">450</span></a>                <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">:</span>
+</span><span id="Alias-451"><a href="#Alias-451"><span class="linenos">451</span></a>                    <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">message</span><span class="p">:</span>
+</span><span id="Alias-452"><a href="#Alias-452"><span class="linenos">452</span></a>                        <span class="n">alias_message</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">[</span><span class="n">key</span><span class="p">]]</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</span><span id="Alias-453"><a href="#Alias-453"><span class="linenos">453</span></a>                <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">alias_message</span><span class="p">)</span>
+</span><span id="Alias-454"><a href="#Alias-454"><span class="linenos">454</span></a>
+</span><span id="Alias-455"><a href="#Alias-455"><span class="linenos">455</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Alias-456"><a href="#Alias-456"><span class="linenos">456</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Alias-457"><a href="#Alias-457"><span class="linenos">457</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Translate messages to an alias.</p>
+
+<p>The "from" configuration key gets a message template and the
+configuration key "to" a (partial) message. The "translate"
+configuration key contains pairs of message keys, where the "from"
+message key is translated to the "to" message key if present in the
+message.</p>
+
+<p>All messages matching the "from" template are received by the Alias
+instance and a message translated by adding the keys and values of the
+"to" message and the translated key-value pairs according to
+"translate" is sent. Keys that are not "sender" and not modified by
+"to" or "translate" are retained.</p>
+
+<p>In the example, the two messages sent by the test are translated by the
+Alias instance and the translated messages are sent by it preserving
+the "content" keys:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Alias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span>
+<span class="gp">... </span>                    <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;translated&quot;</span><span class="p">},</span>
+<span class="gp">... </span>                    <span class="s2">&quot;translate&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s1">&#39;from&#39;</span><span class="p">:</span> <span class="s2">&quot;old&quot;</span><span class="p">,</span> <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="s2">&quot;new&quot;</span><span class="p">}]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">,</span> <span class="s2">&quot;old&quot;</span><span class="p">:</span> <span class="s2">&quot;content&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Second Message&quot;</span><span class="p">,</span> <span class="s2">&quot;old&quot;</span><span class="p">:</span> <span class="s2">&quot;content&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+<span class="go">         &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>
+<span class="go">         &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</code></pre>
+</div>
+
+<p>An Alias instance can also translate to a list of messages instead of
+a single message:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Alias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span>
+<span class="gp">... </span>                    <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;first&quot;</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;second&quot;</span><span class="p">}],</span>
+<span class="gp">... </span>                    <span class="s2">&quot;translate&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s1">&#39;from&#39;</span><span class="p">:</span> <span class="s2">&quot;old&quot;</span><span class="p">,</span> <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="s2">&quot;new&quot;</span><span class="p">}]}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Message&quot;</span><span class="p">,</span> <span class="s2">&quot;old&quot;</span><span class="p">:</span> <span class="s2">&quot;content&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;first&#39;}},</span>
+<span class="go">                   {&#39;id&#39;: {&#39;const&#39;: &#39;second&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;first&#39;,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;second&#39;,</span>
+<span class="go">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>
+</code></pre>
+</div>
+
+<p>The "from" key is required:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Alias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Alias&quot;</span><span class="p">}},</span> <span class="p">[]))</span>
+<span class="go">data must contain [&#39;from&#39;] properties</span>
+<span class="go">Configuration for &#39;Test Alias&#39; is not valid.</span>
+</code></pre>
+</div>
+
+<p>The "from" key has to contain a message template and the "to" key a
+(partial) message, i.e., both have to be JSON objects:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Alias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span> <span class="p">[]))</span>
+<span class="go">data.from must be object</span>
+<span class="go">Configuration for &#39;Test Alias&#39; is not valid.</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Alias&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                    <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span>
+<span class="gp">... </span>                    <span class="s2">&quot;to&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span> <span class="p">[]))</span>
+<span class="go">data.to cannot be validated by any definition</span>
+<span class="go">Configuration for &#39;Test Alias&#39; is not valid.</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Alias.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<input id="Alias.CONF_SCHEMA-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="Alias.CONF_SCHEMA-view-value"></label><span class="default_value">{&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;}, &#39;to&#39;: {&#39;anyOf&#39;: [{&#39;type&#39;: &#39;object&#39;}, {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}]}, &#39;translate&#39;: {&#39;type&#39;: &#39;array&#39;, &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;, &#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;string&#39;}, &#39;to&#39;: {&#39;type&#39;: &#39;string&#39;}}}}}, &#39;required&#39;: [&#39;from&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Alias.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Alias plugin configuration.</p>
+
+<p>Required configuration keys:</p>
+
+<ul>
+<li>'from': template of messages to be translated.</li>
+</ul>
+
+<p>Optional configuration keys:</p>
+
+<ul>
+<li>'to': translated message(s) to be sent.</li>
+<li>'translate': array of pairs of keys to be translated.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Alias.process_conf" class="classattr">
+                                        <input id="Alias.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Alias.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Alias.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Alias.process_conf-424"><a href="#Alias.process_conf-424"><span class="linenos">424</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Alias.process_conf-425"><a href="#Alias.process_conf-425"><span class="linenos">425</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Alias.process_conf-426"><a href="#Alias.process_conf-426"><span class="linenos">426</span></a>        <span class="n">sends</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="Alias.process_conf-427"><a href="#Alias.process_conf-427"><span class="linenos">427</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="p">[]</span>
+</span><span id="Alias.process_conf-428"><a href="#Alias.process_conf-428"><span class="linenos">428</span></a>        <span class="k">if</span> <span class="s2">&quot;to&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+</span><span id="Alias.process_conf-429"><a href="#Alias.process_conf-429"><span class="linenos">429</span></a>            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">],</span> <span class="nb">list</span><span class="p">):</span>
+</span><span id="Alias.process_conf-430"><a href="#Alias.process_conf-430"><span class="linenos">430</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]</span>
+</span><span id="Alias.process_conf-431"><a href="#Alias.process_conf-431"><span class="linenos">431</span></a>                <span class="k">for</span> <span class="n">to</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]:</span>
+</span><span id="Alias.process_conf-432"><a href="#Alias.process_conf-432"><span class="linenos">432</span></a>                    <span class="n">sends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="n">to</span><span class="p">))</span>
+</span><span id="Alias.process_conf-433"><a href="#Alias.process_conf-433"><span class="linenos">433</span></a>            <span class="k">else</span><span class="p">:</span>
+</span><span id="Alias.process_conf-434"><a href="#Alias.process_conf-434"><span class="linenos">434</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_to</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]]</span>
+</span><span id="Alias.process_conf-435"><a href="#Alias.process_conf-435"><span class="linenos">435</span></a>                <span class="n">sends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]))</span>
+</span><span id="Alias.process_conf-436"><a href="#Alias.process_conf-436"><span class="linenos">436</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span id="Alias.process_conf-437"><a href="#Alias.process_conf-437"><span class="linenos">437</span></a>        <span class="k">if</span> <span class="s2">&quot;translate&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">:</span>
+</span><span id="Alias.process_conf-438"><a href="#Alias.process_conf-438"><span class="linenos">438</span></a>            <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;translate&quot;</span><span class="p">]:</span>
+</span><span id="Alias.process_conf-439"><a href="#Alias.process_conf-439"><span class="linenos">439</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">_translate</span><span class="p">[</span><span class="n">pair</span><span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">pair</span><span class="p">[</span><span class="s2">&quot;to&quot;</span><span class="p">]</span>
+</span><span id="Alias.process_conf-440"><a href="#Alias.process_conf-440"><span class="linenos">440</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Alias.process_conf-441"><a href="#Alias.process_conf-441"><span class="linenos">441</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;Alias&quot;</span><span class="p">,</span> <span class="n">sends</span><span class="p">,</span> <span class="p">[([</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;from&quot;</span><span class="p">]],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_alias</span><span class="p">)]</span>
+</span><span id="Alias.process_conf-442"><a href="#Alias.process_conf-442"><span class="linenos">442</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Alias.run" class="classattr">
+                                        <input id="Alias.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Alias.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Alias.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Alias.run-455"><a href="#Alias.run-455"><span class="linenos">455</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Alias.run-456"><a href="#Alias.run-456"><span class="linenos">456</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Alias.run-457"><a href="#Alias.run-457"><span class="linenos">457</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Alias.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Alias.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Alias.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Alias.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Counter">
+                            <input id="Counter-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Counter</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Counter-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Counter"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Counter-460"><a href="#Counter-460"><span class="linenos">460</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Counter</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Counter-461"><a href="#Counter-461"><span class="linenos">461</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Count messages confirming to a given template.</span>
+</span><span id="Counter-462"><a href="#Counter-462"><span class="linenos">462</span></a>
+</span><span id="Counter-463"><a href="#Counter-463"><span class="linenos">463</span></a><span class="sd">    The plugin counts messages confirming to the given template. The</span>
+</span><span id="Counter-464"><a href="#Counter-464"><span class="linenos">464</span></a><span class="sd">    counter can be queried and reset by commands. The &#39;reset&#39; command also</span>
+</span><span id="Counter-465"><a href="#Counter-465"><span class="linenos">465</span></a><span class="sd">    queries the last count before the reset:</span>
+</span><span id="Counter-466"><a href="#Counter-466"><span class="linenos">466</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Counter-467"><a href="#Counter-467"><span class="linenos">467</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Counter-468"><a href="#Counter-468"><span class="linenos">468</span></a><span class="sd">    ...     {&quot;Test Counter&quot;: {&quot;plugin&quot;: &quot;Counter&quot;,</span>
+</span><span id="Counter-469"><a href="#Counter-469"><span class="linenos">469</span></a><span class="sd">    ...                       &quot;count&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}}}},</span>
+</span><span id="Counter-470"><a href="#Counter-470"><span class="linenos">470</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;},</span>
+</span><span id="Counter-471"><a href="#Counter-471"><span class="linenos">471</span></a><span class="sd">    ...      {&quot;id&quot;: 42}, {&quot;id&quot;: 42}, {&quot;id&quot;: 49},</span>
+</span><span id="Counter-472"><a href="#Counter-472"><span class="linenos">472</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;},</span>
+</span><span id="Counter-473"><a href="#Counter-473"><span class="linenos">473</span></a><span class="sd">    ...      {&quot;id&quot;: 42}, {&quot;id&quot;: 42}, {&quot;id&quot;: 42},</span>
+</span><span id="Counter-474"><a href="#Counter-474"><span class="linenos">474</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;reset&quot;},</span>
+</span><span id="Counter-475"><a href="#Counter-475"><span class="linenos">475</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;},</span>
+</span><span id="Counter-476"><a href="#Counter-476"><span class="linenos">476</span></a><span class="sd">    ...      {&quot;id&quot;: 42}, {&quot;id&quot;: 42}, {&quot;id&quot;: 42},</span>
+</span><span id="Counter-477"><a href="#Counter-477"><span class="linenos">477</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test Counter&quot;, &quot;command&quot;: &quot;get count&quot;}]))</span>
+</span><span id="Counter-478"><a href="#Counter-478"><span class="linenos">478</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="Counter-479"><a href="#Counter-479"><span class="linenos">479</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Counter-480"><a href="#Counter-480"><span class="linenos">480</span></a><span class="sd">             &#39;client&#39;: &#39;Test Counter&#39;, &#39;plugin&#39;: &#39;Counter&#39;,</span>
+</span><span id="Counter-481"><a href="#Counter-481"><span class="linenos">481</span></a><span class="sd">             &#39;sends&#39;: [{&#39;count&#39;: {&#39;type&#39;: &#39;integer&#39;}}],</span>
+</span><span id="Counter-482"><a href="#Counter-482"><span class="linenos">482</span></a><span class="sd">             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}},</span>
+</span><span id="Counter-483"><a href="#Counter-483"><span class="linenos">483</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>
+</span><span id="Counter-484"><a href="#Counter-484"><span class="linenos">484</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;get count&#39;}},</span>
+</span><span id="Counter-485"><a href="#Counter-485"><span class="linenos">485</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>
+</span><span id="Counter-486"><a href="#Counter-486"><span class="linenos">486</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;reset&#39;}}]}</span>
+</span><span id="Counter-487"><a href="#Counter-487"><span class="linenos">487</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="Counter-488"><a href="#Counter-488"><span class="linenos">488</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="Counter-489"><a href="#Counter-489"><span class="linenos">489</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-490"><a href="#Counter-490"><span class="linenos">490</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>
+</span><span id="Counter-491"><a href="#Counter-491"><span class="linenos">491</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="Counter-492"><a href="#Counter-492"><span class="linenos">492</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-493"><a href="#Counter-493"><span class="linenos">493</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 49}</span>
+</span><span id="Counter-494"><a href="#Counter-494"><span class="linenos">494</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="Counter-495"><a href="#Counter-495"><span class="linenos">495</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="Counter-496"><a href="#Counter-496"><span class="linenos">496</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-497"><a href="#Counter-497"><span class="linenos">497</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 2,</span>
+</span><span id="Counter-498"><a href="#Counter-498"><span class="linenos">498</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="Counter-499"><a href="#Counter-499"><span class="linenos">499</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-500"><a href="#Counter-500"><span class="linenos">500</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-501"><a href="#Counter-501"><span class="linenos">501</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="Counter-502"><a href="#Counter-502"><span class="linenos">502</span></a><span class="sd">             &#39;command&#39;: &#39;reset&#39;}</span>
+</span><span id="Counter-503"><a href="#Counter-503"><span class="linenos">503</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="Counter-504"><a href="#Counter-504"><span class="linenos">504</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="Counter-505"><a href="#Counter-505"><span class="linenos">505</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 5,</span>
+</span><span id="Counter-506"><a href="#Counter-506"><span class="linenos">506</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="Counter-507"><a href="#Counter-507"><span class="linenos">507</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-508"><a href="#Counter-508"><span class="linenos">508</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>
+</span><span id="Counter-509"><a href="#Counter-509"><span class="linenos">509</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="Counter-510"><a href="#Counter-510"><span class="linenos">510</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-511"><a href="#Counter-511"><span class="linenos">511</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+</span><span id="Counter-512"><a href="#Counter-512"><span class="linenos">512</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+</span><span id="Counter-513"><a href="#Counter-513"><span class="linenos">513</span></a><span class="sd">             &#39;command&#39;: &#39;get count&#39;}</span>
+</span><span id="Counter-514"><a href="#Counter-514"><span class="linenos">514</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 3,</span>
+</span><span id="Counter-515"><a href="#Counter-515"><span class="linenos">515</span></a><span class="sd">             &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</span><span id="Counter-516"><a href="#Counter-516"><span class="linenos">516</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Counter-517"><a href="#Counter-517"><span class="linenos">517</span></a>
+</span><span id="Counter-518"><a href="#Counter-518"><span class="linenos">518</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Counter-519"><a href="#Counter-519"><span class="linenos">519</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
+</span><span id="Counter-520"><a href="#Counter-520"><span class="linenos">520</span></a>            <span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">},</span>
+</span><span id="Counter-521"><a href="#Counter-521"><span class="linenos">521</span></a>            <span class="s2">&quot;date format&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">:</span> <span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S&quot;</span><span class="p">},</span>
+</span><span id="Counter-522"><a href="#Counter-522"><span class="linenos">522</span></a>        <span class="p">},</span>
+</span><span id="Counter-523"><a href="#Counter-523"><span class="linenos">523</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;count&quot;</span><span class="p">],</span>
+</span><span id="Counter-524"><a href="#Counter-524"><span class="linenos">524</span></a>    <span class="p">}</span>
+</span><span id="Counter-525"><a href="#Counter-525"><span class="linenos">525</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Counter plugin configuration.</span>
+</span><span id="Counter-526"><a href="#Counter-526"><span class="linenos">526</span></a>
+</span><span id="Counter-527"><a href="#Counter-527"><span class="linenos">527</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="Counter-528"><a href="#Counter-528"><span class="linenos">528</span></a>
+</span><span id="Counter-529"><a href="#Counter-529"><span class="linenos">529</span></a><span class="sd">    - &#39;count&#39;: template of messages to be counted.</span>
+</span><span id="Counter-530"><a href="#Counter-530"><span class="linenos">530</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Counter-531"><a href="#Counter-531"><span class="linenos">531</span></a>
+</span><span id="Counter-532"><a href="#Counter-532"><span class="linenos">532</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter-533"><a href="#Counter-533"><span class="linenos">533</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Counter-534"><a href="#Counter-534"><span class="linenos">534</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_since</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="Counter-535"><a href="#Counter-535"><span class="linenos">535</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Counter-536"><a href="#Counter-536"><span class="linenos">536</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Counter-537"><a href="#Counter-537"><span class="linenos">537</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Counter-538"><a href="#Counter-538"><span class="linenos">538</span></a>            <span class="s2">&quot;Counter&quot;</span><span class="p">,</span>
+</span><span id="Counter-539"><a href="#Counter-539"><span class="linenos">539</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;integer&quot;</span><span class="p">}})],</span>
+</span><span id="Counter-540"><a href="#Counter-540"><span class="linenos">540</span></a>            <span class="p">[</span>
+</span><span id="Counter-541"><a href="#Counter-541"><span class="linenos">541</span></a>                <span class="p">([</span><span class="n">MessageTemplate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;count&quot;</span><span class="p">])],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span><span class="p">),</span>
+</span><span id="Counter-542"><a href="#Counter-542"><span class="linenos">542</span></a>                <span class="p">(</span>
+</span><span id="Counter-543"><a href="#Counter-543"><span class="linenos">543</span></a>                    <span class="p">[</span>
+</span><span id="Counter-544"><a href="#Counter-544"><span class="linenos">544</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Counter-545"><a href="#Counter-545"><span class="linenos">545</span></a>                            <span class="p">{</span>
+</span><span id="Counter-546"><a href="#Counter-546"><span class="linenos">546</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Counter-547"><a href="#Counter-547"><span class="linenos">547</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">},</span>
+</span><span id="Counter-548"><a href="#Counter-548"><span class="linenos">548</span></a>                            <span class="p">}</span>
+</span><span id="Counter-549"><a href="#Counter-549"><span class="linenos">549</span></a>                        <span class="p">)</span>
+</span><span id="Counter-550"><a href="#Counter-550"><span class="linenos">550</span></a>                    <span class="p">],</span>
+</span><span id="Counter-551"><a href="#Counter-551"><span class="linenos">551</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_count</span><span class="p">,</span>
+</span><span id="Counter-552"><a href="#Counter-552"><span class="linenos">552</span></a>                <span class="p">),</span>
+</span><span id="Counter-553"><a href="#Counter-553"><span class="linenos">553</span></a>                <span class="p">(</span>
+</span><span id="Counter-554"><a href="#Counter-554"><span class="linenos">554</span></a>                    <span class="p">[</span>
+</span><span id="Counter-555"><a href="#Counter-555"><span class="linenos">555</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Counter-556"><a href="#Counter-556"><span class="linenos">556</span></a>                            <span class="p">{</span>
+</span><span id="Counter-557"><a href="#Counter-557"><span class="linenos">557</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Counter-558"><a href="#Counter-558"><span class="linenos">558</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;reset&quot;</span><span class="p">},</span>
+</span><span id="Counter-559"><a href="#Counter-559"><span class="linenos">559</span></a>                            <span class="p">}</span>
+</span><span id="Counter-560"><a href="#Counter-560"><span class="linenos">560</span></a>                        <span class="p">)</span>
+</span><span id="Counter-561"><a href="#Counter-561"><span class="linenos">561</span></a>                    <span class="p">],</span>
+</span><span id="Counter-562"><a href="#Counter-562"><span class="linenos">562</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_reset</span><span class="p">,</span>
+</span><span id="Counter-563"><a href="#Counter-563"><span class="linenos">563</span></a>                <span class="p">),</span>
+</span><span id="Counter-564"><a href="#Counter-564"><span class="linenos">564</span></a>            <span class="p">],</span>
+</span><span id="Counter-565"><a href="#Counter-565"><span class="linenos">565</span></a>        <span class="p">)</span>
+</span><span id="Counter-566"><a href="#Counter-566"><span class="linenos">566</span></a>
+</span><span id="Counter-567"><a href="#Counter-567"><span class="linenos">567</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_count</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter-568"><a href="#Counter-568"><span class="linenos">568</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">+=</span> <span class="mi">1</span>
+</span><span id="Counter-569"><a href="#Counter-569"><span class="linenos">569</span></a>
+</span><span id="Counter-570"><a href="#Counter-570"><span class="linenos">570</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_get_count</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter-571"><a href="#Counter-571"><span class="linenos">571</span></a>        <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="Counter-572"><a href="#Counter-572"><span class="linenos">572</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="Counter-573"><a href="#Counter-573"><span class="linenos">573</span></a>            <span class="n">Message</span><span class="p">(</span>
+</span><span id="Counter-574"><a href="#Counter-574"><span class="linenos">574</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span><span class="p">,</span> <span class="s2">&quot;since&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_since</span><span class="p">,</span> <span class="s2">&quot;until&quot;</span><span class="p">:</span> <span class="n">now</span><span class="p">}</span>
+</span><span id="Counter-575"><a href="#Counter-575"><span class="linenos">575</span></a>            <span class="p">)</span>
+</span><span id="Counter-576"><a href="#Counter-576"><span class="linenos">576</span></a>        <span class="p">)</span>
+</span><span id="Counter-577"><a href="#Counter-577"><span class="linenos">577</span></a>
+</span><span id="Counter-578"><a href="#Counter-578"><span class="linenos">578</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_reset</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter-579"><a href="#Counter-579"><span class="linenos">579</span></a>        <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="Counter-580"><a href="#Counter-580"><span class="linenos">580</span></a>        <span class="n">counter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span>
+</span><span id="Counter-581"><a href="#Counter-581"><span class="linenos">581</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Counter-582"><a href="#Counter-582"><span class="linenos">582</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="Counter-583"><a href="#Counter-583"><span class="linenos">583</span></a>            <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="n">counter</span><span class="p">,</span> <span class="s2">&quot;since&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_since</span><span class="p">,</span> <span class="s2">&quot;until&quot;</span><span class="p">:</span> <span class="n">now</span><span class="p">})</span>
+</span><span id="Counter-584"><a href="#Counter-584"><span class="linenos">584</span></a>        <span class="p">)</span>
+</span><span id="Counter-585"><a href="#Counter-585"><span class="linenos">585</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_since</span> <span class="o">=</span> <span class="n">now</span>
+</span><span id="Counter-586"><a href="#Counter-586"><span class="linenos">586</span></a>
+</span><span id="Counter-587"><a href="#Counter-587"><span class="linenos">587</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter-588"><a href="#Counter-588"><span class="linenos">588</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Counter-589"><a href="#Counter-589"><span class="linenos">589</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Count messages confirming to a given template.</p>
+
+<p>The plugin counts messages confirming to the given template. The
+counter can be queried and reset by commands. The 'reset' command also
+queries the last count before the reset:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Counter&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Counter&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                      <span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}}}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Counter&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">49</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Counter&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Counter&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;reset&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Counter&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Counter&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Counter&#39;, &#39;plugin&#39;: &#39;Counter&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;count&#39;: {&#39;type&#39;: &#39;integer&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}},</span>
+<span class="go">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;get count&#39;}},</span>
+<span class="go">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;reset&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get count&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>
+<span class="go">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 49}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get count&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 2,</span>
+<span class="go">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;reset&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get count&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 5,</span>
+<span class="go">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>
+<span class="go">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get count&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 3,</span>
+<span class="go">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Counter.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<input id="Counter.CONF_SCHEMA-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="Counter.CONF_SCHEMA-view-value"></label><span class="default_value">{&#39;properties&#39;: {&#39;count&#39;: {&#39;type&#39;: &#39;object&#39;}, &#39;date format&#39;: {&#39;type&#39;: &#39;string&#39;, &#39;default&#39;: &#39;%Y-%m-%d %H:%M:%S&#39;}}, &#39;required&#39;: [&#39;count&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Counter.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Counter plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'count': template of messages to be counted.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Counter.process_conf" class="classattr">
+                                        <input id="Counter.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Counter.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Counter.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Counter.process_conf-532"><a href="#Counter.process_conf-532"><span class="linenos">532</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter.process_conf-533"><a href="#Counter.process_conf-533"><span class="linenos">533</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Counter.process_conf-534"><a href="#Counter.process_conf-534"><span class="linenos">534</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_since</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;date format&quot;</span><span class="p">])</span>
+</span><span id="Counter.process_conf-535"><a href="#Counter.process_conf-535"><span class="linenos">535</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_counter</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Counter.process_conf-536"><a href="#Counter.process_conf-536"><span class="linenos">536</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Counter.process_conf-537"><a href="#Counter.process_conf-537"><span class="linenos">537</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Counter.process_conf-538"><a href="#Counter.process_conf-538"><span class="linenos">538</span></a>            <span class="s2">&quot;Counter&quot;</span><span class="p">,</span>
+</span><span id="Counter.process_conf-539"><a href="#Counter.process_conf-539"><span class="linenos">539</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;integer&quot;</span><span class="p">}})],</span>
+</span><span id="Counter.process_conf-540"><a href="#Counter.process_conf-540"><span class="linenos">540</span></a>            <span class="p">[</span>
+</span><span id="Counter.process_conf-541"><a href="#Counter.process_conf-541"><span class="linenos">541</span></a>                <span class="p">([</span><span class="n">MessageTemplate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;count&quot;</span><span class="p">])],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span><span class="p">),</span>
+</span><span id="Counter.process_conf-542"><a href="#Counter.process_conf-542"><span class="linenos">542</span></a>                <span class="p">(</span>
+</span><span id="Counter.process_conf-543"><a href="#Counter.process_conf-543"><span class="linenos">543</span></a>                    <span class="p">[</span>
+</span><span id="Counter.process_conf-544"><a href="#Counter.process_conf-544"><span class="linenos">544</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Counter.process_conf-545"><a href="#Counter.process_conf-545"><span class="linenos">545</span></a>                            <span class="p">{</span>
+</span><span id="Counter.process_conf-546"><a href="#Counter.process_conf-546"><span class="linenos">546</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Counter.process_conf-547"><a href="#Counter.process_conf-547"><span class="linenos">547</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get count&quot;</span><span class="p">},</span>
+</span><span id="Counter.process_conf-548"><a href="#Counter.process_conf-548"><span class="linenos">548</span></a>                            <span class="p">}</span>
+</span><span id="Counter.process_conf-549"><a href="#Counter.process_conf-549"><span class="linenos">549</span></a>                        <span class="p">)</span>
+</span><span id="Counter.process_conf-550"><a href="#Counter.process_conf-550"><span class="linenos">550</span></a>                    <span class="p">],</span>
+</span><span id="Counter.process_conf-551"><a href="#Counter.process_conf-551"><span class="linenos">551</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_get_count</span><span class="p">,</span>
+</span><span id="Counter.process_conf-552"><a href="#Counter.process_conf-552"><span class="linenos">552</span></a>                <span class="p">),</span>
+</span><span id="Counter.process_conf-553"><a href="#Counter.process_conf-553"><span class="linenos">553</span></a>                <span class="p">(</span>
+</span><span id="Counter.process_conf-554"><a href="#Counter.process_conf-554"><span class="linenos">554</span></a>                    <span class="p">[</span>
+</span><span id="Counter.process_conf-555"><a href="#Counter.process_conf-555"><span class="linenos">555</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Counter.process_conf-556"><a href="#Counter.process_conf-556"><span class="linenos">556</span></a>                            <span class="p">{</span>
+</span><span id="Counter.process_conf-557"><a href="#Counter.process_conf-557"><span class="linenos">557</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Counter.process_conf-558"><a href="#Counter.process_conf-558"><span class="linenos">558</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;reset&quot;</span><span class="p">},</span>
+</span><span id="Counter.process_conf-559"><a href="#Counter.process_conf-559"><span class="linenos">559</span></a>                            <span class="p">}</span>
+</span><span id="Counter.process_conf-560"><a href="#Counter.process_conf-560"><span class="linenos">560</span></a>                        <span class="p">)</span>
+</span><span id="Counter.process_conf-561"><a href="#Counter.process_conf-561"><span class="linenos">561</span></a>                    <span class="p">],</span>
+</span><span id="Counter.process_conf-562"><a href="#Counter.process_conf-562"><span class="linenos">562</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_reset</span><span class="p">,</span>
+</span><span id="Counter.process_conf-563"><a href="#Counter.process_conf-563"><span class="linenos">563</span></a>                <span class="p">),</span>
+</span><span id="Counter.process_conf-564"><a href="#Counter.process_conf-564"><span class="linenos">564</span></a>            <span class="p">],</span>
+</span><span id="Counter.process_conf-565"><a href="#Counter.process_conf-565"><span class="linenos">565</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Counter.run" class="classattr">
+                                        <input id="Counter.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Counter.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Counter.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Counter.run-587"><a href="#Counter.run-587"><span class="linenos">587</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Counter.run-588"><a href="#Counter.run-588"><span class="linenos">588</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Counter.run-589"><a href="#Counter.run-589"><span class="linenos">589</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Counter.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Counter.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Counter.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Counter.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Date">
+                            <input id="Date-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Date</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Date-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Date"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Date-592"><a href="#Date-592"><span class="linenos">592</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Date</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Date-593"><a href="#Date-593"><span class="linenos">593</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send message with current date.</span>
+</span><span id="Date-594"><a href="#Date-594"><span class="linenos">594</span></a>
+</span><span id="Date-595"><a href="#Date-595"><span class="linenos">595</span></a><span class="sd">    The plugin reacts to &#39;get date&#39; commands by sending messages with</span>
+</span><span id="Date-596"><a href="#Date-596"><span class="linenos">596</span></a><span class="sd">    a &#39;date&#39; key:</span>
+</span><span id="Date-597"><a href="#Date-597"><span class="linenos">597</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Date-598"><a href="#Date-598"><span class="linenos">598</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Date-599"><a href="#Date-599"><span class="linenos">599</span></a><span class="sd">    ...     {&quot;Test Date&quot;: {&quot;plugin&quot;: &quot;Date&quot;}},</span>
+</span><span id="Date-600"><a href="#Date-600"><span class="linenos">600</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Date&quot;, &quot;command&quot;: &quot;get date&quot;}]))</span>
+</span><span id="Date-601"><a href="#Date-601"><span class="linenos">601</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="Date-602"><a href="#Date-602"><span class="linenos">602</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Date-603"><a href="#Date-603"><span class="linenos">603</span></a><span class="sd">             &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>
+</span><span id="Date-604"><a href="#Date-604"><span class="linenos">604</span></a><span class="sd">             &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="Date-605"><a href="#Date-605"><span class="linenos">605</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>
+</span><span id="Date-606"><a href="#Date-606"><span class="linenos">606</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>
+</span><span id="Date-607"><a href="#Date-607"><span class="linenos">607</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>
+</span><span id="Date-608"><a href="#Date-608"><span class="linenos">608</span></a><span class="sd">             &#39;command&#39;: &#39;get date&#39;}</span>
+</span><span id="Date-609"><a href="#Date-609"><span class="linenos">609</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>
+</span><span id="Date-610"><a href="#Date-610"><span class="linenos">610</span></a>
+</span><span id="Date-611"><a href="#Date-611"><span class="linenos">611</span></a><span class="sd">    The format of the date can be configured with the &#39;format&#39;</span>
+</span><span id="Date-612"><a href="#Date-612"><span class="linenos">612</span></a><span class="sd">    configuration key:</span>
+</span><span id="Date-613"><a href="#Date-613"><span class="linenos">613</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Date-614"><a href="#Date-614"><span class="linenos">614</span></a><span class="sd">    ...     {&quot;Test Date&quot;: {&quot;plugin&quot;: &quot;Date&quot;,</span>
+</span><span id="Date-615"><a href="#Date-615"><span class="linenos">615</span></a><span class="sd">    ...                    &quot;format&quot;: &quot;%Y%m%d%H%M%S%f&quot;}},</span>
+</span><span id="Date-616"><a href="#Date-616"><span class="linenos">616</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test Date&quot;, &quot;command&quot;: &quot;get date&quot;}]))</span>
+</span><span id="Date-617"><a href="#Date-617"><span class="linenos">617</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+</span><span id="Date-618"><a href="#Date-618"><span class="linenos">618</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Date-619"><a href="#Date-619"><span class="linenos">619</span></a><span class="sd">             &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>
+</span><span id="Date-620"><a href="#Date-620"><span class="linenos">620</span></a><span class="sd">             &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="Date-621"><a href="#Date-621"><span class="linenos">621</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>
+</span><span id="Date-622"><a href="#Date-622"><span class="linenos">622</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>
+</span><span id="Date-623"><a href="#Date-623"><span class="linenos">623</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>
+</span><span id="Date-624"><a href="#Date-624"><span class="linenos">624</span></a><span class="sd">             &#39;command&#39;: &#39;get date&#39;}</span>
+</span><span id="Date-625"><a href="#Date-625"><span class="linenos">625</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>
+</span><span id="Date-626"><a href="#Date-626"><span class="linenos">626</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Date-627"><a href="#Date-627"><span class="linenos">627</span></a>
+</span><span id="Date-628"><a href="#Date-628"><span class="linenos">628</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Date-629"><a href="#Date-629"><span class="linenos">629</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">:</span> <span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S&quot;</span><span class="p">}}</span>
+</span><span id="Date-630"><a href="#Date-630"><span class="linenos">630</span></a>    <span class="p">}</span>
+</span><span id="Date-631"><a href="#Date-631"><span class="linenos">631</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Date plugin configuration.</span>
+</span><span id="Date-632"><a href="#Date-632"><span class="linenos">632</span></a>
+</span><span id="Date-633"><a href="#Date-633"><span class="linenos">633</span></a><span class="sd">    Optional configuration key:</span>
+</span><span id="Date-634"><a href="#Date-634"><span class="linenos">634</span></a>
+</span><span id="Date-635"><a href="#Date-635"><span class="linenos">635</span></a><span class="sd">    - &#39;format&#39;: format for the sent datetime string.</span>
+</span><span id="Date-636"><a href="#Date-636"><span class="linenos">636</span></a><span class="sd">                Default: &#39;%Y-%m-%d %H:%M:%S&#39;</span>
+</span><span id="Date-637"><a href="#Date-637"><span class="linenos">637</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Date-638"><a href="#Date-638"><span class="linenos">638</span></a>
+</span><span id="Date-639"><a href="#Date-639"><span class="linenos">639</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Date-640"><a href="#Date-640"><span class="linenos">640</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Date-641"><a href="#Date-641"><span class="linenos">641</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Date-642"><a href="#Date-642"><span class="linenos">642</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Date-643"><a href="#Date-643"><span class="linenos">643</span></a>            <span class="s2">&quot;Date&quot;</span><span class="p">,</span>
+</span><span id="Date-644"><a href="#Date-644"><span class="linenos">644</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}})],</span>
+</span><span id="Date-645"><a href="#Date-645"><span class="linenos">645</span></a>            <span class="p">[</span>
+</span><span id="Date-646"><a href="#Date-646"><span class="linenos">646</span></a>                <span class="p">(</span>
+</span><span id="Date-647"><a href="#Date-647"><span class="linenos">647</span></a>                    <span class="p">[</span>
+</span><span id="Date-648"><a href="#Date-648"><span class="linenos">648</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Date-649"><a href="#Date-649"><span class="linenos">649</span></a>                            <span class="p">{</span>
+</span><span id="Date-650"><a href="#Date-650"><span class="linenos">650</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Date-651"><a href="#Date-651"><span class="linenos">651</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get date&quot;</span><span class="p">},</span>
+</span><span id="Date-652"><a href="#Date-652"><span class="linenos">652</span></a>                            <span class="p">}</span>
+</span><span id="Date-653"><a href="#Date-653"><span class="linenos">653</span></a>                        <span class="p">)</span>
+</span><span id="Date-654"><a href="#Date-654"><span class="linenos">654</span></a>                    <span class="p">],</span>
+</span><span id="Date-655"><a href="#Date-655"><span class="linenos">655</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_date</span><span class="p">,</span>
+</span><span id="Date-656"><a href="#Date-656"><span class="linenos">656</span></a>                <span class="p">)</span>
+</span><span id="Date-657"><a href="#Date-657"><span class="linenos">657</span></a>            <span class="p">],</span>
+</span><span id="Date-658"><a href="#Date-658"><span class="linenos">658</span></a>        <span class="p">)</span>
+</span><span id="Date-659"><a href="#Date-659"><span class="linenos">659</span></a>
+</span><span id="Date-660"><a href="#Date-660"><span class="linenos">660</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_date</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Date-661"><a href="#Date-661"><span class="linenos">661</span></a>        <span class="n">date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">])</span>
+</span><span id="Date-662"><a href="#Date-662"><span class="linenos">662</span></a>        <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="n">date</span><span class="p">}))</span>
+</span><span id="Date-663"><a href="#Date-663"><span class="linenos">663</span></a>
+</span><span id="Date-664"><a href="#Date-664"><span class="linenos">664</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Date-665"><a href="#Date-665"><span class="linenos">665</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Date-666"><a href="#Date-666"><span class="linenos">666</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send message with current date.</p>
+
+<p>The plugin reacts to 'get date' commands by sending messages with
+a 'date' key:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Date&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Date&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Date&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get date&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get date&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>
+</code></pre>
+</div>
+
+<p>The format of the date can be configured with the 'format'
+configuration key:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Date&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Date&quot;</span><span class="p">,</span>
+<span class="gp">... </span>                   <span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="s2">&quot;%Y%m</span><span class="si">%d</span><span class="s2">%H%M%S</span><span class="si">%f</span><span class="s2">&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Date&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;get date&quot;</span><span class="p">}]))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;get date&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Date.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;format&#39;: {&#39;type&#39;: &#39;string&#39;, &#39;default&#39;: &#39;%Y-%m-%d %H:%M:%S&#39;}}}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Date.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Date plugin configuration.</p>
+
+<p>Optional configuration key:</p>
+
+<ul>
+<li>'format': format for the sent datetime string.
+Default: '%Y-%m-%d %H:%M:%S'</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Date.process_conf" class="classattr">
+                                        <input id="Date.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Date.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Date.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Date.process_conf-639"><a href="#Date.process_conf-639"><span class="linenos">639</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Date.process_conf-640"><a href="#Date.process_conf-640"><span class="linenos">640</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Date.process_conf-641"><a href="#Date.process_conf-641"><span class="linenos">641</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Date.process_conf-642"><a href="#Date.process_conf-642"><span class="linenos">642</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Date.process_conf-643"><a href="#Date.process_conf-643"><span class="linenos">643</span></a>            <span class="s2">&quot;Date&quot;</span><span class="p">,</span>
+</span><span id="Date.process_conf-644"><a href="#Date.process_conf-644"><span class="linenos">644</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}})],</span>
+</span><span id="Date.process_conf-645"><a href="#Date.process_conf-645"><span class="linenos">645</span></a>            <span class="p">[</span>
+</span><span id="Date.process_conf-646"><a href="#Date.process_conf-646"><span class="linenos">646</span></a>                <span class="p">(</span>
+</span><span id="Date.process_conf-647"><a href="#Date.process_conf-647"><span class="linenos">647</span></a>                    <span class="p">[</span>
+</span><span id="Date.process_conf-648"><a href="#Date.process_conf-648"><span class="linenos">648</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Date.process_conf-649"><a href="#Date.process_conf-649"><span class="linenos">649</span></a>                            <span class="p">{</span>
+</span><span id="Date.process_conf-650"><a href="#Date.process_conf-650"><span class="linenos">650</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Date.process_conf-651"><a href="#Date.process_conf-651"><span class="linenos">651</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;get date&quot;</span><span class="p">},</span>
+</span><span id="Date.process_conf-652"><a href="#Date.process_conf-652"><span class="linenos">652</span></a>                            <span class="p">}</span>
+</span><span id="Date.process_conf-653"><a href="#Date.process_conf-653"><span class="linenos">653</span></a>                        <span class="p">)</span>
+</span><span id="Date.process_conf-654"><a href="#Date.process_conf-654"><span class="linenos">654</span></a>                    <span class="p">],</span>
+</span><span id="Date.process_conf-655"><a href="#Date.process_conf-655"><span class="linenos">655</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_date</span><span class="p">,</span>
+</span><span id="Date.process_conf-656"><a href="#Date.process_conf-656"><span class="linenos">656</span></a>                <span class="p">)</span>
+</span><span id="Date.process_conf-657"><a href="#Date.process_conf-657"><span class="linenos">657</span></a>            <span class="p">],</span>
+</span><span id="Date.process_conf-658"><a href="#Date.process_conf-658"><span class="linenos">658</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Date.run" class="classattr">
+                                        <input id="Date.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Date.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Date.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Date.run-664"><a href="#Date.run-664"><span class="linenos">664</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Date.run-665"><a href="#Date.run-665"><span class="linenos">665</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Date.run-666"><a href="#Date.run-666"><span class="linenos">666</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Date.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Date.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Date.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Date.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "../search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `../${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/controlpi_plugins/wait.html b/doc/api/controlpi_plugins/wait.html
new file mode 100644 (file)
index 0000000..7d5f0c5
--- /dev/null
@@ -0,0 +1,1585 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>controlpi_plugins.wait API documentation</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>            <a class="pdoc-button module-list-button" href="../controlpi_plugins.html">
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-in-left" viewBox="0 0 16 16">
+  <path fill-rule="evenodd" d="M10 3.5a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 1 1 0v2A1.5 1.5 0 0 1 9.5 14h-8A1.5 1.5 0 0 1 0 12.5v-9A1.5 1.5 0 0 1 1.5 2h8A1.5 1.5 0 0 1 11 3.5v2a.5.5 0 0 1-1 0v-2z"/>
+  <path fill-rule="evenodd" d="M4.146 8.354a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H14.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3z"/>
+</svg>                &nbsp;controlpi_plugins</a>
+
+
+            <input type="search" placeholder="Search..." role="searchbox" aria-label="search"
+                   pattern=".+" required>
+
+
+
+            <h2>API Documentation</h2>
+                <ul class="memberlist">
+            <li>
+                    <a class="class" href="#Wait">Wait</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Wait.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Wait.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Wait.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#GenericWait">GenericWait</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#GenericWait.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#GenericWait.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#GenericWait.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Timer">Timer</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Timer.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Timer.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Timer.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+            <li>
+                    <a class="class" href="#Periodic">Periodic</a>
+                            <ul class="memberlist">
+                        <li>
+                                <a class="variable" href="#Periodic.CONF_SCHEMA">CONF_SCHEMA</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Periodic.process_conf">process_conf</a>
+                        </li>
+                        <li>
+                                <a class="function" href="#Periodic.run">run</a>
+                        </li>
+                </ul>
+
+            </li>
+    </ul>
+
+
+
+        <a class="attribution" title="pdoc: Python API documentation generator" href="https://pdoc.dev" target="_blank">
+            built with <span class="visually-hidden">pdoc</span><img
+                alt="pdoc logo"
+                src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"/>
+        </a>
+</div>
+    </nav>
+    <main class="pdoc">
+            <section class="module-info">
+                    <h1 class="modulename">
+<a href="./../controlpi_plugins.html">controlpi_plugins</a><wbr>.wait    </h1>
+
+                        <div class="docstring"><p>Provide waiting/sleeping plugins for all kinds of systems.</p>
+
+<ul>
+<li>Wait waits for time defined in configuration and sends "finished" event.</li>
+<li>GenericWait waits for time defined in "wait" command and sends "finished"
+event with "id" string defined in "wait" command.</li>
+</ul>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test Wait&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Wait&quot;</span><span class="p">,</span> <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Test GenericWait&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;GenericWait&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test GenericWait&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.02</span><span class="p">,</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;Long Wait&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test Wait&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">}],</span> <span class="mf">0.025</span><span class="p">))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Wait&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>
+<span class="go">                    &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>
+<span class="go">                       &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+<span class="go">                       &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+<span class="go">         &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+                        <input id="mod-wait-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+
+                        <label class="view-source-button" for="mod-wait-view-source"><span>View Source</span></label>
+
+                        <div class="pdoc-code codehilite"><pre><span></span><span id="L-1"><a href="#L-1"><span class="linenos">  1</span></a><span class="sd">&quot;&quot;&quot;Provide waiting/sleeping plugins for all kinds of systems.</span>
+</span><span id="L-2"><a href="#L-2"><span class="linenos">  2</span></a>
+</span><span id="L-3"><a href="#L-3"><span class="linenos">  3</span></a><span class="sd">- Wait waits for time defined in configuration and sends &quot;finished&quot; event.</span>
+</span><span id="L-4"><a href="#L-4"><span class="linenos">  4</span></a><span class="sd">- GenericWait waits for time defined in &quot;wait&quot; command and sends &quot;finished&quot;</span>
+</span><span id="L-5"><a href="#L-5"><span class="linenos">  5</span></a><span class="sd">  event with &quot;id&quot; string defined in &quot;wait&quot; command.</span>
+</span><span id="L-6"><a href="#L-6"><span class="linenos">  6</span></a>
+</span><span id="L-7"><a href="#L-7"><span class="linenos">  7</span></a><span class="sd">&gt;&gt;&gt; import controlpi</span>
+</span><span id="L-8"><a href="#L-8"><span class="linenos">  8</span></a><span class="sd">&gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-9"><a href="#L-9"><span class="linenos">  9</span></a><span class="sd">...     {&quot;Test Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.01},</span>
+</span><span id="L-10"><a href="#L-10"><span class="linenos"> 10</span></a><span class="sd">...      &quot;Test GenericWait&quot;: {&quot;plugin&quot;: &quot;GenericWait&quot;}},</span>
+</span><span id="L-11"><a href="#L-11"><span class="linenos"> 11</span></a><span class="sd">...     [{&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,</span>
+</span><span id="L-12"><a href="#L-12"><span class="linenos"> 12</span></a><span class="sd">...       &quot;seconds&quot;: 0.02, &quot;id&quot;: &quot;Long Wait&quot;},</span>
+</span><span id="L-13"><a href="#L-13"><span class="linenos"> 13</span></a><span class="sd">...      {&quot;target&quot;: &quot;Test Wait&quot;, &quot;command&quot;: &quot;wait&quot;}], 0.025))</span>
+</span><span id="L-14"><a href="#L-14"><span class="linenos"> 14</span></a><span class="sd">... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-15"><a href="#L-15"><span class="linenos"> 15</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-16"><a href="#L-16"><span class="linenos"> 16</span></a><span class="sd">         &#39;client&#39;: &#39;Test Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+</span><span id="L-17"><a href="#L-17"><span class="linenos"> 17</span></a><span class="sd">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+</span><span id="L-18"><a href="#L-18"><span class="linenos"> 18</span></a><span class="sd">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Wait&#39;},</span>
+</span><span id="L-19"><a href="#L-19"><span class="linenos"> 19</span></a><span class="sd">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+</span><span id="L-20"><a href="#L-20"><span class="linenos"> 20</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-21"><a href="#L-21"><span class="linenos"> 21</span></a><span class="sd">         &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>
+</span><span id="L-22"><a href="#L-22"><span class="linenos"> 22</span></a><span class="sd">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>
+</span><span id="L-23"><a href="#L-23"><span class="linenos"> 23</span></a><span class="sd">                    &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-24"><a href="#L-24"><span class="linenos"> 24</span></a><span class="sd">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>
+</span><span id="L-25"><a href="#L-25"><span class="linenos"> 25</span></a><span class="sd">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>
+</span><span id="L-26"><a href="#L-26"><span class="linenos"> 26</span></a><span class="sd">                       &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-27"><a href="#L-27"><span class="linenos"> 27</span></a><span class="sd">                       &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>
+</span><span id="L-28"><a href="#L-28"><span class="linenos"> 28</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+</span><span id="L-29"><a href="#L-29"><span class="linenos"> 29</span></a><span class="sd">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</span><span id="L-30"><a href="#L-30"><span class="linenos"> 30</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+</span><span id="L-31"><a href="#L-31"><span class="linenos"> 31</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="L-32"><a href="#L-32"><span class="linenos"> 32</span></a><span class="sd">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+</span><span id="L-33"><a href="#L-33"><span class="linenos"> 33</span></a><span class="sd">         &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</span><span id="L-34"><a href="#L-34"><span class="linenos"> 34</span></a><span class="sd">&quot;&quot;&quot;</span>
+</span><span id="L-35"><a href="#L-35"><span class="linenos"> 35</span></a>
+</span><span id="L-36"><a href="#L-36"><span class="linenos"> 36</span></a><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
+</span><span id="L-37"><a href="#L-37"><span class="linenos"> 37</span></a>
+</span><span id="L-38"><a href="#L-38"><span class="linenos"> 38</span></a><span class="kn">from</span><span class="w"> </span><span class="nn">controlpi</span><span class="w"> </span><span class="kn">import</span> <span class="n">BasePlugin</span><span class="p">,</span> <span class="n">Message</span><span class="p">,</span> <span class="n">MessageTemplate</span>
+</span><span id="L-39"><a href="#L-39"><span class="linenos"> 39</span></a>
+</span><span id="L-40"><a href="#L-40"><span class="linenos"> 40</span></a>
+</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Wait</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Wait for time defined in configuration.</span>
+</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a>
+</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="sd">    The &quot;seconds&quot; configuration key gets the number of seconds to wait after</span>
+</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a><span class="sd">    receiving a &quot;wait&quot; command before sending the &quot;finished&quot; event:</span>
+</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-48"><a href="#L-48"><span class="linenos"> 48</span></a><span class="sd">    ...     {&quot;Long Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.02},</span>
+</span><span id="L-49"><a href="#L-49"><span class="linenos"> 49</span></a><span class="sd">    ...      &quot;Short Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.01}},</span>
+</span><span id="L-50"><a href="#L-50"><span class="linenos"> 50</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Long Wait&quot;, &quot;command&quot;: &quot;wait&quot;},</span>
+</span><span id="L-51"><a href="#L-51"><span class="linenos"> 51</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Short Wait&quot;, &quot;command&quot;: &quot;wait&quot;}], 0.025))</span>
+</span><span id="L-52"><a href="#L-52"><span class="linenos"> 52</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-53"><a href="#L-53"><span class="linenos"> 53</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-54"><a href="#L-54"><span class="linenos"> 54</span></a><span class="sd">             &#39;client&#39;: &#39;Long Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Long Wait&#39;},</span>
+</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a><span class="sd">             &#39;client&#39;: &#39;Short Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Short Wait&#39;},</span>
+</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+</span><span id="L-63"><a href="#L-63"><span class="linenos"> 63</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Long Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+</span><span id="L-64"><a href="#L-64"><span class="linenos"> 64</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Short Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+</span><span id="L-65"><a href="#L-65"><span class="linenos"> 65</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Short Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="L-66"><a href="#L-66"><span class="linenos"> 66</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Long Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="L-67"><a href="#L-67"><span class="linenos"> 67</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-68"><a href="#L-68"><span class="linenos"> 68</span></a>
+</span><span id="L-69"><a href="#L-69"><span class="linenos"> 69</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-70"><a href="#L-70"><span class="linenos"> 70</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">}},</span>
+</span><span id="L-71"><a href="#L-71"><span class="linenos"> 71</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span>
+</span><span id="L-72"><a href="#L-72"><span class="linenos"> 72</span></a>    <span class="p">}</span>
+</span><span id="L-73"><a href="#L-73"><span class="linenos"> 73</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Wait plugin configuration.</span>
+</span><span id="L-74"><a href="#L-74"><span class="linenos"> 74</span></a>
+</span><span id="L-75"><a href="#L-75"><span class="linenos"> 75</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a>
+</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd">    - &#39;seconds&#39;: number of seconds to wait.</span>
+</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a>
+</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-85"><a href="#L-85"><span class="linenos"> 85</span></a>            <span class="s2">&quot;Wait&quot;</span><span class="p">,</span>
+</span><span id="L-86"><a href="#L-86"><span class="linenos"> 86</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}})],</span>
+</span><span id="L-87"><a href="#L-87"><span class="linenos"> 87</span></a>            <span class="p">[</span>
+</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a>                <span class="p">(</span>
+</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a>                    <span class="p">[</span>
+</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</span></a>                            <span class="p">{</span>
+</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a>                            <span class="p">}</span>
+</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a>                        <span class="p">)</span>
+</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a>                    <span class="p">],</span>
+</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_wait</span><span class="p">,</span>
+</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a>                <span class="p">)</span>
+</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a>            <span class="p">],</span>
+</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a>        <span class="p">)</span>
+</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a>
+</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a>        <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">wait_coroutine</span><span class="p">():</span>
+</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}))</span>
+</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a>
+</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a>        <span class="c1"># Done in separate task to not block queue awaiting this callback:</span>
+</span><span id="L-108"><a href="#L-108"><span class="linenos">108</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">wait_coroutine</span><span class="p">())</span>
+</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a>
+</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a>        <span class="k">pass</span>
+</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a>
+</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a>
+</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="k">class</span><span class="w"> </span><span class="nc">GenericWait</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Wait for time defined in &quot;wait&quot; command.</span>
+</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a>
+</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a><span class="sd">    The &quot;wait&quot; command has message keys &quot;seconds&quot; defining the seconds to</span>
+</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a><span class="sd">    wait and &quot;id&quot; defining a string to be sent back in the &quot;finished&quot; event</span>
+</span><span id="L-122"><a href="#L-122"><span class="linenos">122</span></a><span class="sd">    after the wait:</span>
+</span><span id="L-123"><a href="#L-123"><span class="linenos">123</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-124"><a href="#L-124"><span class="linenos">124</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-125"><a href="#L-125"><span class="linenos">125</span></a><span class="sd">    ...     {&quot;Test GenericWait&quot;: {&quot;plugin&quot;: &quot;GenericWait&quot;}},</span>
+</span><span id="L-126"><a href="#L-126"><span class="linenos">126</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,</span>
+</span><span id="L-127"><a href="#L-127"><span class="linenos">127</span></a><span class="sd">    ...       &quot;seconds&quot;: 0.02, &quot;id&quot;: &quot;Long Wait&quot;},</span>
+</span><span id="L-128"><a href="#L-128"><span class="linenos">128</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,</span>
+</span><span id="L-129"><a href="#L-129"><span class="linenos">129</span></a><span class="sd">    ...       &quot;seconds&quot;: 0.01, &quot;id&quot;: &quot;Short Wait&quot;}], 0.025))</span>
+</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-131"><a href="#L-131"><span class="linenos">131</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a><span class="sd">             &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>
+</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>
+</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="sd">                        &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>
+</span><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>
+</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a><span class="sd">                           &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a><span class="sd">                           &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>
+</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a><span class="sd">             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a><span class="sd">             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.01, &#39;id&#39;: &#39;Short Wait&#39;}</span>
+</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a><span class="sd">             &#39;id&#39;: &#39;Short Wait&#39;}</span>
+</span><span id="L-145"><a href="#L-145"><span class="linenos">145</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a><span class="sd">             &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-148"><a href="#L-148"><span class="linenos">148</span></a>
+</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="L-150"><a href="#L-150"><span class="linenos">150</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for GenericWait plugin configuration.</span>
+</span><span id="L-151"><a href="#L-151"><span class="linenos">151</span></a>
+</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a><span class="sd">    There are no required or optional configuration keys.</span>
+</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a>
+</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-160"><a href="#L-160"><span class="linenos">160</span></a>            <span class="s2">&quot;GenericWait&quot;</span><span class="p">,</span>
+</span><span id="L-161"><a href="#L-161"><span class="linenos">161</span></a>            <span class="p">[</span>
+</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">},</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}</span>
+</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a>                <span class="p">)</span>
+</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a>            <span class="p">],</span>
+</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a>            <span class="p">[</span>
+</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a>                <span class="p">(</span>
+</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a>                    <span class="p">[</span>
+</span><span id="L-169"><a href="#L-169"><span class="linenos">169</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-170"><a href="#L-170"><span class="linenos">170</span></a>                            <span class="p">{</span>
+</span><span id="L-171"><a href="#L-171"><span class="linenos">171</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-172"><a href="#L-172"><span class="linenos">172</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+</span><span id="L-173"><a href="#L-173"><span class="linenos">173</span></a>                                <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">},</span>
+</span><span id="L-174"><a href="#L-174"><span class="linenos">174</span></a>                                <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="L-175"><a href="#L-175"><span class="linenos">175</span></a>                            <span class="p">}</span>
+</span><span id="L-176"><a href="#L-176"><span class="linenos">176</span></a>                        <span class="p">)</span>
+</span><span id="L-177"><a href="#L-177"><span class="linenos">177</span></a>                    <span class="p">],</span>
+</span><span id="L-178"><a href="#L-178"><span class="linenos">178</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_wait</span><span class="p">,</span>
+</span><span id="L-179"><a href="#L-179"><span class="linenos">179</span></a>                <span class="p">)</span>
+</span><span id="L-180"><a href="#L-180"><span class="linenos">180</span></a>            <span class="p">],</span>
+</span><span id="L-181"><a href="#L-181"><span class="linenos">181</span></a>        <span class="p">)</span>
+</span><span id="L-182"><a href="#L-182"><span class="linenos">182</span></a>
+</span><span id="L-183"><a href="#L-183"><span class="linenos">183</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-184"><a href="#L-184"><span class="linenos">184</span></a>        <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">wait_coroutine</span><span class="p">():</span>
+</span><span id="L-185"><a href="#L-185"><span class="linenos">185</span></a>            <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span> <span class="nb">float</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span>
+</span><span id="L-186"><a href="#L-186"><span class="linenos">186</span></a>                <span class="n">message</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span> <span class="nb">int</span>
+</span><span id="L-187"><a href="#L-187"><span class="linenos">187</span></a>            <span class="p">)</span>
+</span><span id="L-188"><a href="#L-188"><span class="linenos">188</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="L-189"><a href="#L-189"><span class="linenos">189</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-190"><a href="#L-190"><span class="linenos">190</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">,</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]})</span>
+</span><span id="L-191"><a href="#L-191"><span class="linenos">191</span></a>            <span class="p">)</span>
+</span><span id="L-192"><a href="#L-192"><span class="linenos">192</span></a>
+</span><span id="L-193"><a href="#L-193"><span class="linenos">193</span></a>        <span class="c1"># Done in separate task to not block queue awaiting this callback:</span>
+</span><span id="L-194"><a href="#L-194"><span class="linenos">194</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">wait_coroutine</span><span class="p">())</span>
+</span><span id="L-195"><a href="#L-195"><span class="linenos">195</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="L-196"><a href="#L-196"><span class="linenos">196</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="L-197"><a href="#L-197"><span class="linenos">197</span></a>
+</span><span id="L-198"><a href="#L-198"><span class="linenos">198</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-199"><a href="#L-199"><span class="linenos">199</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-200"><a href="#L-200"><span class="linenos">200</span></a>        <span class="k">pass</span>
+</span><span id="L-201"><a href="#L-201"><span class="linenos">201</span></a>
+</span><span id="L-202"><a href="#L-202"><span class="linenos">202</span></a>
+</span><span id="L-203"><a href="#L-203"><span class="linenos">203</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Timer</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-204"><a href="#L-204"><span class="linenos">204</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Timer that can be started and cancelled.</span>
+</span><span id="L-205"><a href="#L-205"><span class="linenos">205</span></a>
+</span><span id="L-206"><a href="#L-206"><span class="linenos">206</span></a><span class="sd">    The &quot;seconds&quot; configuration key gets the number of seconds to wait after</span>
+</span><span id="L-207"><a href="#L-207"><span class="linenos">207</span></a><span class="sd">    receiving a &quot;start&quot; command before sending the &quot;finished&quot; event.</span>
+</span><span id="L-208"><a href="#L-208"><span class="linenos">208</span></a><span class="sd">    The &quot;cancel&quot; command cancels all outstanding &quot;finished&quot; events and sends</span>
+</span><span id="L-209"><a href="#L-209"><span class="linenos">209</span></a><span class="sd">    a corresponding &quot;cancelled&quot; event:</span>
+</span><span id="L-210"><a href="#L-210"><span class="linenos">210</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-211"><a href="#L-211"><span class="linenos">211</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-212"><a href="#L-212"><span class="linenos">212</span></a><span class="sd">    ...     {&quot;Timer&quot;: {&quot;plugin&quot;: &quot;Timer&quot;, &quot;seconds&quot;: 0.01}},</span>
+</span><span id="L-213"><a href="#L-213"><span class="linenos">213</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;},</span>
+</span><span id="L-214"><a href="#L-214"><span class="linenos">214</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;},</span>
+</span><span id="L-215"><a href="#L-215"><span class="linenos">215</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;cancel&quot;},</span>
+</span><span id="L-216"><a href="#L-216"><span class="linenos">216</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;},</span>
+</span><span id="L-217"><a href="#L-217"><span class="linenos">217</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;}], 0.015))</span>
+</span><span id="L-218"><a href="#L-218"><span class="linenos">218</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-219"><a href="#L-219"><span class="linenos">219</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-220"><a href="#L-220"><span class="linenos">220</span></a><span class="sd">             &#39;client&#39;: &#39;Timer&#39;, &#39;plugin&#39;: &#39;Timer&#39;,</span>
+</span><span id="L-221"><a href="#L-221"><span class="linenos">221</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}},</span>
+</span><span id="L-222"><a href="#L-222"><span class="linenos">222</span></a><span class="sd">                       {&#39;event&#39;: {&#39;const&#39;: &#39;cancelled&#39;}}],</span>
+</span><span id="L-223"><a href="#L-223"><span class="linenos">223</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>
+</span><span id="L-224"><a href="#L-224"><span class="linenos">224</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;start&#39;}},</span>
+</span><span id="L-225"><a href="#L-225"><span class="linenos">225</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>
+</span><span id="L-226"><a href="#L-226"><span class="linenos">226</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;cancel&#39;}}]}</span>
+</span><span id="L-227"><a href="#L-227"><span class="linenos">227</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="L-228"><a href="#L-228"><span class="linenos">228</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="L-229"><a href="#L-229"><span class="linenos">229</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;cancel&#39;}</span>
+</span><span id="L-230"><a href="#L-230"><span class="linenos">230</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="L-231"><a href="#L-231"><span class="linenos">231</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;cancelled&#39;, &#39;count&#39;: 2}</span>
+</span><span id="L-232"><a href="#L-232"><span class="linenos">232</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="L-233"><a href="#L-233"><span class="linenos">233</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="L-234"><a href="#L-234"><span class="linenos">234</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="L-235"><a href="#L-235"><span class="linenos">235</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-236"><a href="#L-236"><span class="linenos">236</span></a>
+</span><span id="L-237"><a href="#L-237"><span class="linenos">237</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-238"><a href="#L-238"><span class="linenos">238</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">}},</span>
+</span><span id="L-239"><a href="#L-239"><span class="linenos">239</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span>
+</span><span id="L-240"><a href="#L-240"><span class="linenos">240</span></a>    <span class="p">}</span>
+</span><span id="L-241"><a href="#L-241"><span class="linenos">241</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Timer plugin configuration.</span>
+</span><span id="L-242"><a href="#L-242"><span class="linenos">242</span></a>
+</span><span id="L-243"><a href="#L-243"><span class="linenos">243</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-244"><a href="#L-244"><span class="linenos">244</span></a>
+</span><span id="L-245"><a href="#L-245"><span class="linenos">245</span></a><span class="sd">    - &#39;seconds&#39;: number of seconds to wait.</span>
+</span><span id="L-246"><a href="#L-246"><span class="linenos">246</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-247"><a href="#L-247"><span class="linenos">247</span></a>
+</span><span id="L-248"><a href="#L-248"><span class="linenos">248</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-249"><a href="#L-249"><span class="linenos">249</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-250"><a href="#L-250"><span class="linenos">250</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="L-251"><a href="#L-251"><span class="linenos">251</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="L-252"><a href="#L-252"><span class="linenos">252</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="L-253"><a href="#L-253"><span class="linenos">253</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-254"><a href="#L-254"><span class="linenos">254</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-255"><a href="#L-255"><span class="linenos">255</span></a>            <span class="s2">&quot;Timer&quot;</span><span class="p">,</span>
+</span><span id="L-256"><a href="#L-256"><span class="linenos">256</span></a>            <span class="p">[</span>
+</span><span id="L-257"><a href="#L-257"><span class="linenos">257</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}}),</span>
+</span><span id="L-258"><a href="#L-258"><span class="linenos">258</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;cancelled&quot;</span><span class="p">}}),</span>
+</span><span id="L-259"><a href="#L-259"><span class="linenos">259</span></a>            <span class="p">],</span>
+</span><span id="L-260"><a href="#L-260"><span class="linenos">260</span></a>            <span class="p">[</span>
+</span><span id="L-261"><a href="#L-261"><span class="linenos">261</span></a>                <span class="p">(</span>
+</span><span id="L-262"><a href="#L-262"><span class="linenos">262</span></a>                    <span class="p">[</span>
+</span><span id="L-263"><a href="#L-263"><span class="linenos">263</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-264"><a href="#L-264"><span class="linenos">264</span></a>                            <span class="p">{</span>
+</span><span id="L-265"><a href="#L-265"><span class="linenos">265</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-266"><a href="#L-266"><span class="linenos">266</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">},</span>
+</span><span id="L-267"><a href="#L-267"><span class="linenos">267</span></a>                            <span class="p">}</span>
+</span><span id="L-268"><a href="#L-268"><span class="linenos">268</span></a>                        <span class="p">)</span>
+</span><span id="L-269"><a href="#L-269"><span class="linenos">269</span></a>                    <span class="p">],</span>
+</span><span id="L-270"><a href="#L-270"><span class="linenos">270</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_start</span><span class="p">,</span>
+</span><span id="L-271"><a href="#L-271"><span class="linenos">271</span></a>                <span class="p">),</span>
+</span><span id="L-272"><a href="#L-272"><span class="linenos">272</span></a>                <span class="p">(</span>
+</span><span id="L-273"><a href="#L-273"><span class="linenos">273</span></a>                    <span class="p">[</span>
+</span><span id="L-274"><a href="#L-274"><span class="linenos">274</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="L-275"><a href="#L-275"><span class="linenos">275</span></a>                            <span class="p">{</span>
+</span><span id="L-276"><a href="#L-276"><span class="linenos">276</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="L-277"><a href="#L-277"><span class="linenos">277</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;cancel&quot;</span><span class="p">},</span>
+</span><span id="L-278"><a href="#L-278"><span class="linenos">278</span></a>                            <span class="p">}</span>
+</span><span id="L-279"><a href="#L-279"><span class="linenos">279</span></a>                        <span class="p">)</span>
+</span><span id="L-280"><a href="#L-280"><span class="linenos">280</span></a>                    <span class="p">],</span>
+</span><span id="L-281"><a href="#L-281"><span class="linenos">281</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_cancel</span><span class="p">,</span>
+</span><span id="L-282"><a href="#L-282"><span class="linenos">282</span></a>                <span class="p">),</span>
+</span><span id="L-283"><a href="#L-283"><span class="linenos">283</span></a>            <span class="p">],</span>
+</span><span id="L-284"><a href="#L-284"><span class="linenos">284</span></a>        <span class="p">)</span>
+</span><span id="L-285"><a href="#L-285"><span class="linenos">285</span></a>
+</span><span id="L-286"><a href="#L-286"><span class="linenos">286</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-287"><a href="#L-287"><span class="linenos">287</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">+=</span> <span class="mi">1</span>
+</span><span id="L-288"><a href="#L-288"><span class="linenos">288</span></a>
+</span><span id="L-289"><a href="#L-289"><span class="linenos">289</span></a>        <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">wait_coroutine</span><span class="p">():</span>
+</span><span id="L-290"><a href="#L-290"><span class="linenos">290</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="L-291"><a href="#L-291"><span class="linenos">291</span></a>            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+</span><span id="L-292"><a href="#L-292"><span class="linenos">292</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">-=</span> <span class="mi">1</span>
+</span><span id="L-293"><a href="#L-293"><span class="linenos">293</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">-=</span> <span class="mi">1</span>
+</span><span id="L-294"><a href="#L-294"><span class="linenos">294</span></a>            <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+</span><span id="L-295"><a href="#L-295"><span class="linenos">295</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">-=</span> <span class="mi">1</span>
+</span><span id="L-296"><a href="#L-296"><span class="linenos">296</span></a>                <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}))</span>
+</span><span id="L-297"><a href="#L-297"><span class="linenos">297</span></a>
+</span><span id="L-298"><a href="#L-298"><span class="linenos">298</span></a>        <span class="c1"># Done in separate task to not block queue awaiting this callback:</span>
+</span><span id="L-299"><a href="#L-299"><span class="linenos">299</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">wait_coroutine</span><span class="p">())</span>
+</span><span id="L-300"><a href="#L-300"><span class="linenos">300</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="L-301"><a href="#L-301"><span class="linenos">301</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="L-302"><a href="#L-302"><span class="linenos">302</span></a>
+</span><span id="L-303"><a href="#L-303"><span class="linenos">303</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_cancel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-304"><a href="#L-304"><span class="linenos">304</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span><span class="p">:</span>
+</span><span id="L-305"><a href="#L-305"><span class="linenos">305</span></a>            <span class="n">cancel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span>
+</span><span id="L-306"><a href="#L-306"><span class="linenos">306</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span>
+</span><span id="L-307"><a href="#L-307"><span class="linenos">307</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="L-308"><a href="#L-308"><span class="linenos">308</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;cancelled&quot;</span><span class="p">,</span> <span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="n">cancel</span><span class="p">})</span>
+</span><span id="L-309"><a href="#L-309"><span class="linenos">309</span></a>            <span class="p">)</span>
+</span><span id="L-310"><a href="#L-310"><span class="linenos">310</span></a>
+</span><span id="L-311"><a href="#L-311"><span class="linenos">311</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-312"><a href="#L-312"><span class="linenos">312</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="L-313"><a href="#L-313"><span class="linenos">313</span></a>        <span class="k">pass</span>
+</span><span id="L-314"><a href="#L-314"><span class="linenos">314</span></a>
+</span><span id="L-315"><a href="#L-315"><span class="linenos">315</span></a>
+</span><span id="L-316"><a href="#L-316"><span class="linenos">316</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Periodic</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="L-317"><a href="#L-317"><span class="linenos">317</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send message periodically.</span>
+</span><span id="L-318"><a href="#L-318"><span class="linenos">318</span></a>
+</span><span id="L-319"><a href="#L-319"><span class="linenos">319</span></a><span class="sd">    The &quot;seconds&quot; configuration key is the period of the repetition:</span>
+</span><span id="L-320"><a href="#L-320"><span class="linenos">320</span></a><span class="sd">    receiving a &quot;wait&quot; command before sending the &quot;finished&quot; event:</span>
+</span><span id="L-321"><a href="#L-321"><span class="linenos">321</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="L-322"><a href="#L-322"><span class="linenos">322</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="L-323"><a href="#L-323"><span class="linenos">323</span></a><span class="sd">    ...     {&quot;Loop&quot;: {&quot;plugin&quot;: &quot;Periodic&quot;, &quot;seconds&quot;: 0.01,</span>
+</span><span id="L-324"><a href="#L-324"><span class="linenos">324</span></a><span class="sd">    ...               &quot;message&quot;: {&quot;key&quot;: &quot;value&quot;}}},</span>
+</span><span id="L-325"><a href="#L-325"><span class="linenos">325</span></a><span class="sd">    ...     [], 0.025))</span>
+</span><span id="L-326"><a href="#L-326"><span class="linenos">326</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="L-327"><a href="#L-327"><span class="linenos">327</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="L-328"><a href="#L-328"><span class="linenos">328</span></a><span class="sd">             &#39;client&#39;: &#39;Loop&#39;, &#39;plugin&#39;: &#39;Periodic&#39;,</span>
+</span><span id="L-329"><a href="#L-329"><span class="linenos">329</span></a><span class="sd">             &#39;sends&#39;: [{&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}], &#39;receives&#39;: []}</span>
+</span><span id="L-330"><a href="#L-330"><span class="linenos">330</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="L-331"><a href="#L-331"><span class="linenos">331</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="L-332"><a href="#L-332"><span class="linenos">332</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-333"><a href="#L-333"><span class="linenos">333</span></a>
+</span><span id="L-334"><a href="#L-334"><span class="linenos">334</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="L-335"><a href="#L-335"><span class="linenos">335</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">},</span> <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}},</span>
+</span><span id="L-336"><a href="#L-336"><span class="linenos">336</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">,</span> <span class="s2">&quot;message&quot;</span><span class="p">],</span>
+</span><span id="L-337"><a href="#L-337"><span class="linenos">337</span></a>    <span class="p">}</span>
+</span><span id="L-338"><a href="#L-338"><span class="linenos">338</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Wait plugin configuration.</span>
+</span><span id="L-339"><a href="#L-339"><span class="linenos">339</span></a>
+</span><span id="L-340"><a href="#L-340"><span class="linenos">340</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="L-341"><a href="#L-341"><span class="linenos">341</span></a>
+</span><span id="L-342"><a href="#L-342"><span class="linenos">342</span></a><span class="sd">    - &#39;seconds&#39;: period of repetition in seconds.</span>
+</span><span id="L-343"><a href="#L-343"><span class="linenos">343</span></a><span class="sd">    - &#39;message&#39;: message to send periodically.</span>
+</span><span id="L-344"><a href="#L-344"><span class="linenos">344</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="L-345"><a href="#L-345"><span class="linenos">345</span></a>
+</span><span id="L-346"><a href="#L-346"><span class="linenos">346</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-347"><a href="#L-347"><span class="linenos">347</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="L-348"><a href="#L-348"><span class="linenos">348</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="L-349"><a href="#L-349"><span class="linenos">349</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="L-350"><a href="#L-350"><span class="linenos">350</span></a>            <span class="s2">&quot;Periodic&quot;</span><span class="p">,</span>
+</span><span id="L-351"><a href="#L-351"><span class="linenos">351</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;message&quot;</span><span class="p">])],</span>
+</span><span id="L-352"><a href="#L-352"><span class="linenos">352</span></a>            <span class="p">[],</span>
+</span><span id="L-353"><a href="#L-353"><span class="linenos">353</span></a>        <span class="p">)</span>
+</span><span id="L-354"><a href="#L-354"><span class="linenos">354</span></a>
+</span><span id="L-355"><a href="#L-355"><span class="linenos">355</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="L-356"><a href="#L-356"><span class="linenos">356</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run periodic loop.&quot;&quot;&quot;</span>
+</span><span id="L-357"><a href="#L-357"><span class="linenos">357</span></a>        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
+</span><span id="L-358"><a href="#L-358"><span class="linenos">358</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="L-359"><a href="#L-359"><span class="linenos">359</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;message&quot;</span><span class="p">]))</span>
+</span></pre></div>
+
+
+            </section>
+                <section id="Wait">
+                            <input id="Wait-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Wait</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Wait-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Wait"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Wait-42"><a href="#Wait-42"><span class="linenos"> 42</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Wait</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Wait-43"><a href="#Wait-43"><span class="linenos"> 43</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Wait for time defined in configuration.</span>
+</span><span id="Wait-44"><a href="#Wait-44"><span class="linenos"> 44</span></a>
+</span><span id="Wait-45"><a href="#Wait-45"><span class="linenos"> 45</span></a><span class="sd">    The &quot;seconds&quot; configuration key gets the number of seconds to wait after</span>
+</span><span id="Wait-46"><a href="#Wait-46"><span class="linenos"> 46</span></a><span class="sd">    receiving a &quot;wait&quot; command before sending the &quot;finished&quot; event:</span>
+</span><span id="Wait-47"><a href="#Wait-47"><span class="linenos"> 47</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Wait-48"><a href="#Wait-48"><span class="linenos"> 48</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Wait-49"><a href="#Wait-49"><span class="linenos"> 49</span></a><span class="sd">    ...     {&quot;Long Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.02},</span>
+</span><span id="Wait-50"><a href="#Wait-50"><span class="linenos"> 50</span></a><span class="sd">    ...      &quot;Short Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.01}},</span>
+</span><span id="Wait-51"><a href="#Wait-51"><span class="linenos"> 51</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Long Wait&quot;, &quot;command&quot;: &quot;wait&quot;},</span>
+</span><span id="Wait-52"><a href="#Wait-52"><span class="linenos"> 52</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Short Wait&quot;, &quot;command&quot;: &quot;wait&quot;}], 0.025))</span>
+</span><span id="Wait-53"><a href="#Wait-53"><span class="linenos"> 53</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Wait-54"><a href="#Wait-54"><span class="linenos"> 54</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Wait-55"><a href="#Wait-55"><span class="linenos"> 55</span></a><span class="sd">             &#39;client&#39;: &#39;Long Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+</span><span id="Wait-56"><a href="#Wait-56"><span class="linenos"> 56</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+</span><span id="Wait-57"><a href="#Wait-57"><span class="linenos"> 57</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Long Wait&#39;},</span>
+</span><span id="Wait-58"><a href="#Wait-58"><span class="linenos"> 58</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+</span><span id="Wait-59"><a href="#Wait-59"><span class="linenos"> 59</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Wait-60"><a href="#Wait-60"><span class="linenos"> 60</span></a><span class="sd">             &#39;client&#39;: &#39;Short Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+</span><span id="Wait-61"><a href="#Wait-61"><span class="linenos"> 61</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+</span><span id="Wait-62"><a href="#Wait-62"><span class="linenos"> 62</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Short Wait&#39;},</span>
+</span><span id="Wait-63"><a href="#Wait-63"><span class="linenos"> 63</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+</span><span id="Wait-64"><a href="#Wait-64"><span class="linenos"> 64</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Long Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+</span><span id="Wait-65"><a href="#Wait-65"><span class="linenos"> 65</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Short Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+</span><span id="Wait-66"><a href="#Wait-66"><span class="linenos"> 66</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Short Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="Wait-67"><a href="#Wait-67"><span class="linenos"> 67</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Long Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="Wait-68"><a href="#Wait-68"><span class="linenos"> 68</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Wait-69"><a href="#Wait-69"><span class="linenos"> 69</span></a>
+</span><span id="Wait-70"><a href="#Wait-70"><span class="linenos"> 70</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Wait-71"><a href="#Wait-71"><span class="linenos"> 71</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">}},</span>
+</span><span id="Wait-72"><a href="#Wait-72"><span class="linenos"> 72</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span>
+</span><span id="Wait-73"><a href="#Wait-73"><span class="linenos"> 73</span></a>    <span class="p">}</span>
+</span><span id="Wait-74"><a href="#Wait-74"><span class="linenos"> 74</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Wait plugin configuration.</span>
+</span><span id="Wait-75"><a href="#Wait-75"><span class="linenos"> 75</span></a>
+</span><span id="Wait-76"><a href="#Wait-76"><span class="linenos"> 76</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="Wait-77"><a href="#Wait-77"><span class="linenos"> 77</span></a>
+</span><span id="Wait-78"><a href="#Wait-78"><span class="linenos"> 78</span></a><span class="sd">    - &#39;seconds&#39;: number of seconds to wait.</span>
+</span><span id="Wait-79"><a href="#Wait-79"><span class="linenos"> 79</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Wait-80"><a href="#Wait-80"><span class="linenos"> 80</span></a>
+</span><span id="Wait-81"><a href="#Wait-81"><span class="linenos"> 81</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Wait-82"><a href="#Wait-82"><span class="linenos"> 82</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Wait-83"><a href="#Wait-83"><span class="linenos"> 83</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="Wait-84"><a href="#Wait-84"><span class="linenos"> 84</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Wait-85"><a href="#Wait-85"><span class="linenos"> 85</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Wait-86"><a href="#Wait-86"><span class="linenos"> 86</span></a>            <span class="s2">&quot;Wait&quot;</span><span class="p">,</span>
+</span><span id="Wait-87"><a href="#Wait-87"><span class="linenos"> 87</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}})],</span>
+</span><span id="Wait-88"><a href="#Wait-88"><span class="linenos"> 88</span></a>            <span class="p">[</span>
+</span><span id="Wait-89"><a href="#Wait-89"><span class="linenos"> 89</span></a>                <span class="p">(</span>
+</span><span id="Wait-90"><a href="#Wait-90"><span class="linenos"> 90</span></a>                    <span class="p">[</span>
+</span><span id="Wait-91"><a href="#Wait-91"><span class="linenos"> 91</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Wait-92"><a href="#Wait-92"><span class="linenos"> 92</span></a>                            <span class="p">{</span>
+</span><span id="Wait-93"><a href="#Wait-93"><span class="linenos"> 93</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Wait-94"><a href="#Wait-94"><span class="linenos"> 94</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+</span><span id="Wait-95"><a href="#Wait-95"><span class="linenos"> 95</span></a>                            <span class="p">}</span>
+</span><span id="Wait-96"><a href="#Wait-96"><span class="linenos"> 96</span></a>                        <span class="p">)</span>
+</span><span id="Wait-97"><a href="#Wait-97"><span class="linenos"> 97</span></a>                    <span class="p">],</span>
+</span><span id="Wait-98"><a href="#Wait-98"><span class="linenos"> 98</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_wait</span><span class="p">,</span>
+</span><span id="Wait-99"><a href="#Wait-99"><span class="linenos"> 99</span></a>                <span class="p">)</span>
+</span><span id="Wait-100"><a href="#Wait-100"><span class="linenos">100</span></a>            <span class="p">],</span>
+</span><span id="Wait-101"><a href="#Wait-101"><span class="linenos">101</span></a>        <span class="p">)</span>
+</span><span id="Wait-102"><a href="#Wait-102"><span class="linenos">102</span></a>
+</span><span id="Wait-103"><a href="#Wait-103"><span class="linenos">103</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Wait-104"><a href="#Wait-104"><span class="linenos">104</span></a>        <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">wait_coroutine</span><span class="p">():</span>
+</span><span id="Wait-105"><a href="#Wait-105"><span class="linenos">105</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="Wait-106"><a href="#Wait-106"><span class="linenos">106</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}))</span>
+</span><span id="Wait-107"><a href="#Wait-107"><span class="linenos">107</span></a>
+</span><span id="Wait-108"><a href="#Wait-108"><span class="linenos">108</span></a>        <span class="c1"># Done in separate task to not block queue awaiting this callback:</span>
+</span><span id="Wait-109"><a href="#Wait-109"><span class="linenos">109</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">wait_coroutine</span><span class="p">())</span>
+</span><span id="Wait-110"><a href="#Wait-110"><span class="linenos">110</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="Wait-111"><a href="#Wait-111"><span class="linenos">111</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="Wait-112"><a href="#Wait-112"><span class="linenos">112</span></a>
+</span><span id="Wait-113"><a href="#Wait-113"><span class="linenos">113</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Wait-114"><a href="#Wait-114"><span class="linenos">114</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Wait-115"><a href="#Wait-115"><span class="linenos">115</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Wait for time defined in configuration.</p>
+
+<p>The "seconds" configuration key gets the number of seconds to wait after
+receiving a "wait" command before sending the "finished" event:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Long Wait&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Wait&quot;</span><span class="p">,</span> <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.02</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="s2">&quot;Short Wait&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Wait&quot;</span><span class="p">,</span> <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Long Wait&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Short Wait&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">}],</span> <span class="mf">0.025</span><span class="p">))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Long Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Long Wait&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Short Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Short Wait&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Long Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Short Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Short Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Long Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Wait.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;}}, &#39;required&#39;: [&#39;seconds&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Wait.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Wait plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'seconds': number of seconds to wait.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Wait.process_conf" class="classattr">
+                                        <input id="Wait.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Wait.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Wait.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Wait.process_conf-81"><a href="#Wait.process_conf-81"><span class="linenos"> 81</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Wait.process_conf-82"><a href="#Wait.process_conf-82"><span class="linenos"> 82</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Wait.process_conf-83"><a href="#Wait.process_conf-83"><span class="linenos"> 83</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="Wait.process_conf-84"><a href="#Wait.process_conf-84"><span class="linenos"> 84</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Wait.process_conf-85"><a href="#Wait.process_conf-85"><span class="linenos"> 85</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Wait.process_conf-86"><a href="#Wait.process_conf-86"><span class="linenos"> 86</span></a>            <span class="s2">&quot;Wait&quot;</span><span class="p">,</span>
+</span><span id="Wait.process_conf-87"><a href="#Wait.process_conf-87"><span class="linenos"> 87</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}})],</span>
+</span><span id="Wait.process_conf-88"><a href="#Wait.process_conf-88"><span class="linenos"> 88</span></a>            <span class="p">[</span>
+</span><span id="Wait.process_conf-89"><a href="#Wait.process_conf-89"><span class="linenos"> 89</span></a>                <span class="p">(</span>
+</span><span id="Wait.process_conf-90"><a href="#Wait.process_conf-90"><span class="linenos"> 90</span></a>                    <span class="p">[</span>
+</span><span id="Wait.process_conf-91"><a href="#Wait.process_conf-91"><span class="linenos"> 91</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Wait.process_conf-92"><a href="#Wait.process_conf-92"><span class="linenos"> 92</span></a>                            <span class="p">{</span>
+</span><span id="Wait.process_conf-93"><a href="#Wait.process_conf-93"><span class="linenos"> 93</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Wait.process_conf-94"><a href="#Wait.process_conf-94"><span class="linenos"> 94</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+</span><span id="Wait.process_conf-95"><a href="#Wait.process_conf-95"><span class="linenos"> 95</span></a>                            <span class="p">}</span>
+</span><span id="Wait.process_conf-96"><a href="#Wait.process_conf-96"><span class="linenos"> 96</span></a>                        <span class="p">)</span>
+</span><span id="Wait.process_conf-97"><a href="#Wait.process_conf-97"><span class="linenos"> 97</span></a>                    <span class="p">],</span>
+</span><span id="Wait.process_conf-98"><a href="#Wait.process_conf-98"><span class="linenos"> 98</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_wait</span><span class="p">,</span>
+</span><span id="Wait.process_conf-99"><a href="#Wait.process_conf-99"><span class="linenos"> 99</span></a>                <span class="p">)</span>
+</span><span id="Wait.process_conf-100"><a href="#Wait.process_conf-100"><span class="linenos">100</span></a>            <span class="p">],</span>
+</span><span id="Wait.process_conf-101"><a href="#Wait.process_conf-101"><span class="linenos">101</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Wait.run" class="classattr">
+                                        <input id="Wait.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Wait.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Wait.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Wait.run-113"><a href="#Wait.run-113"><span class="linenos">113</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Wait.run-114"><a href="#Wait.run-114"><span class="linenos">114</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Wait.run-115"><a href="#Wait.run-115"><span class="linenos">115</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Wait.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Wait.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Wait.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Wait.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="GenericWait">
+                            <input id="GenericWait-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">GenericWait</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="GenericWait-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#GenericWait"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="GenericWait-118"><a href="#GenericWait-118"><span class="linenos">118</span></a><span class="k">class</span><span class="w"> </span><span class="nc">GenericWait</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="GenericWait-119"><a href="#GenericWait-119"><span class="linenos">119</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Wait for time defined in &quot;wait&quot; command.</span>
+</span><span id="GenericWait-120"><a href="#GenericWait-120"><span class="linenos">120</span></a>
+</span><span id="GenericWait-121"><a href="#GenericWait-121"><span class="linenos">121</span></a><span class="sd">    The &quot;wait&quot; command has message keys &quot;seconds&quot; defining the seconds to</span>
+</span><span id="GenericWait-122"><a href="#GenericWait-122"><span class="linenos">122</span></a><span class="sd">    wait and &quot;id&quot; defining a string to be sent back in the &quot;finished&quot; event</span>
+</span><span id="GenericWait-123"><a href="#GenericWait-123"><span class="linenos">123</span></a><span class="sd">    after the wait:</span>
+</span><span id="GenericWait-124"><a href="#GenericWait-124"><span class="linenos">124</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="GenericWait-125"><a href="#GenericWait-125"><span class="linenos">125</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="GenericWait-126"><a href="#GenericWait-126"><span class="linenos">126</span></a><span class="sd">    ...     {&quot;Test GenericWait&quot;: {&quot;plugin&quot;: &quot;GenericWait&quot;}},</span>
+</span><span id="GenericWait-127"><a href="#GenericWait-127"><span class="linenos">127</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,</span>
+</span><span id="GenericWait-128"><a href="#GenericWait-128"><span class="linenos">128</span></a><span class="sd">    ...       &quot;seconds&quot;: 0.02, &quot;id&quot;: &quot;Long Wait&quot;},</span>
+</span><span id="GenericWait-129"><a href="#GenericWait-129"><span class="linenos">129</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,</span>
+</span><span id="GenericWait-130"><a href="#GenericWait-130"><span class="linenos">130</span></a><span class="sd">    ...       &quot;seconds&quot;: 0.01, &quot;id&quot;: &quot;Short Wait&quot;}], 0.025))</span>
+</span><span id="GenericWait-131"><a href="#GenericWait-131"><span class="linenos">131</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="GenericWait-132"><a href="#GenericWait-132"><span class="linenos">132</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="GenericWait-133"><a href="#GenericWait-133"><span class="linenos">133</span></a><span class="sd">             &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>
+</span><span id="GenericWait-134"><a href="#GenericWait-134"><span class="linenos">134</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>
+</span><span id="GenericWait-135"><a href="#GenericWait-135"><span class="linenos">135</span></a><span class="sd">                        &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+</span><span id="GenericWait-136"><a href="#GenericWait-136"><span class="linenos">136</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>
+</span><span id="GenericWait-137"><a href="#GenericWait-137"><span class="linenos">137</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>
+</span><span id="GenericWait-138"><a href="#GenericWait-138"><span class="linenos">138</span></a><span class="sd">                           &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+</span><span id="GenericWait-139"><a href="#GenericWait-139"><span class="linenos">139</span></a><span class="sd">                           &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>
+</span><span id="GenericWait-140"><a href="#GenericWait-140"><span class="linenos">140</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+</span><span id="GenericWait-141"><a href="#GenericWait-141"><span class="linenos">141</span></a><span class="sd">             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</span><span id="GenericWait-142"><a href="#GenericWait-142"><span class="linenos">142</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+</span><span id="GenericWait-143"><a href="#GenericWait-143"><span class="linenos">143</span></a><span class="sd">             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.01, &#39;id&#39;: &#39;Short Wait&#39;}</span>
+</span><span id="GenericWait-144"><a href="#GenericWait-144"><span class="linenos">144</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+</span><span id="GenericWait-145"><a href="#GenericWait-145"><span class="linenos">145</span></a><span class="sd">             &#39;id&#39;: &#39;Short Wait&#39;}</span>
+</span><span id="GenericWait-146"><a href="#GenericWait-146"><span class="linenos">146</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+</span><span id="GenericWait-147"><a href="#GenericWait-147"><span class="linenos">147</span></a><span class="sd">             &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</span><span id="GenericWait-148"><a href="#GenericWait-148"><span class="linenos">148</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="GenericWait-149"><a href="#GenericWait-149"><span class="linenos">149</span></a>
+</span><span id="GenericWait-150"><a href="#GenericWait-150"><span class="linenos">150</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="kc">True</span>
+</span><span id="GenericWait-151"><a href="#GenericWait-151"><span class="linenos">151</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for GenericWait plugin configuration.</span>
+</span><span id="GenericWait-152"><a href="#GenericWait-152"><span class="linenos">152</span></a>
+</span><span id="GenericWait-153"><a href="#GenericWait-153"><span class="linenos">153</span></a><span class="sd">    There are no required or optional configuration keys.</span>
+</span><span id="GenericWait-154"><a href="#GenericWait-154"><span class="linenos">154</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="GenericWait-155"><a href="#GenericWait-155"><span class="linenos">155</span></a>
+</span><span id="GenericWait-156"><a href="#GenericWait-156"><span class="linenos">156</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="GenericWait-157"><a href="#GenericWait-157"><span class="linenos">157</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="GenericWait-158"><a href="#GenericWait-158"><span class="linenos">158</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="GenericWait-159"><a href="#GenericWait-159"><span class="linenos">159</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="GenericWait-160"><a href="#GenericWait-160"><span class="linenos">160</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="GenericWait-161"><a href="#GenericWait-161"><span class="linenos">161</span></a>            <span class="s2">&quot;GenericWait&quot;</span><span class="p">,</span>
+</span><span id="GenericWait-162"><a href="#GenericWait-162"><span class="linenos">162</span></a>            <span class="p">[</span>
+</span><span id="GenericWait-163"><a href="#GenericWait-163"><span class="linenos">163</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="GenericWait-164"><a href="#GenericWait-164"><span class="linenos">164</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">},</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}</span>
+</span><span id="GenericWait-165"><a href="#GenericWait-165"><span class="linenos">165</span></a>                <span class="p">)</span>
+</span><span id="GenericWait-166"><a href="#GenericWait-166"><span class="linenos">166</span></a>            <span class="p">],</span>
+</span><span id="GenericWait-167"><a href="#GenericWait-167"><span class="linenos">167</span></a>            <span class="p">[</span>
+</span><span id="GenericWait-168"><a href="#GenericWait-168"><span class="linenos">168</span></a>                <span class="p">(</span>
+</span><span id="GenericWait-169"><a href="#GenericWait-169"><span class="linenos">169</span></a>                    <span class="p">[</span>
+</span><span id="GenericWait-170"><a href="#GenericWait-170"><span class="linenos">170</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="GenericWait-171"><a href="#GenericWait-171"><span class="linenos">171</span></a>                            <span class="p">{</span>
+</span><span id="GenericWait-172"><a href="#GenericWait-172"><span class="linenos">172</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="GenericWait-173"><a href="#GenericWait-173"><span class="linenos">173</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+</span><span id="GenericWait-174"><a href="#GenericWait-174"><span class="linenos">174</span></a>                                <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">},</span>
+</span><span id="GenericWait-175"><a href="#GenericWait-175"><span class="linenos">175</span></a>                                <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="GenericWait-176"><a href="#GenericWait-176"><span class="linenos">176</span></a>                            <span class="p">}</span>
+</span><span id="GenericWait-177"><a href="#GenericWait-177"><span class="linenos">177</span></a>                        <span class="p">)</span>
+</span><span id="GenericWait-178"><a href="#GenericWait-178"><span class="linenos">178</span></a>                    <span class="p">],</span>
+</span><span id="GenericWait-179"><a href="#GenericWait-179"><span class="linenos">179</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_wait</span><span class="p">,</span>
+</span><span id="GenericWait-180"><a href="#GenericWait-180"><span class="linenos">180</span></a>                <span class="p">)</span>
+</span><span id="GenericWait-181"><a href="#GenericWait-181"><span class="linenos">181</span></a>            <span class="p">],</span>
+</span><span id="GenericWait-182"><a href="#GenericWait-182"><span class="linenos">182</span></a>        <span class="p">)</span>
+</span><span id="GenericWait-183"><a href="#GenericWait-183"><span class="linenos">183</span></a>
+</span><span id="GenericWait-184"><a href="#GenericWait-184"><span class="linenos">184</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_wait</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="GenericWait-185"><a href="#GenericWait-185"><span class="linenos">185</span></a>        <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">wait_coroutine</span><span class="p">():</span>
+</span><span id="GenericWait-186"><a href="#GenericWait-186"><span class="linenos">186</span></a>            <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span> <span class="nb">float</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span>
+</span><span id="GenericWait-187"><a href="#GenericWait-187"><span class="linenos">187</span></a>                <span class="n">message</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span> <span class="nb">int</span>
+</span><span id="GenericWait-188"><a href="#GenericWait-188"><span class="linenos">188</span></a>            <span class="p">)</span>
+</span><span id="GenericWait-189"><a href="#GenericWait-189"><span class="linenos">189</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="GenericWait-190"><a href="#GenericWait-190"><span class="linenos">190</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="GenericWait-191"><a href="#GenericWait-191"><span class="linenos">191</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">,</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="n">message</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]})</span>
+</span><span id="GenericWait-192"><a href="#GenericWait-192"><span class="linenos">192</span></a>            <span class="p">)</span>
+</span><span id="GenericWait-193"><a href="#GenericWait-193"><span class="linenos">193</span></a>
+</span><span id="GenericWait-194"><a href="#GenericWait-194"><span class="linenos">194</span></a>        <span class="c1"># Done in separate task to not block queue awaiting this callback:</span>
+</span><span id="GenericWait-195"><a href="#GenericWait-195"><span class="linenos">195</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">wait_coroutine</span><span class="p">())</span>
+</span><span id="GenericWait-196"><a href="#GenericWait-196"><span class="linenos">196</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="GenericWait-197"><a href="#GenericWait-197"><span class="linenos">197</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="GenericWait-198"><a href="#GenericWait-198"><span class="linenos">198</span></a>
+</span><span id="GenericWait-199"><a href="#GenericWait-199"><span class="linenos">199</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="GenericWait-200"><a href="#GenericWait-200"><span class="linenos">200</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="GenericWait-201"><a href="#GenericWait-201"><span class="linenos">201</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Wait for time defined in "wait" command.</p>
+
+<p>The "wait" command has message keys "seconds" defining the seconds to
+wait and "id" defining a string to be sent back in the "finished" event
+after the wait:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Test GenericWait&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;GenericWait&quot;</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test GenericWait&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.02</span><span class="p">,</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;Long Wait&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Test GenericWait&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">,</span>
+<span class="gp">... </span>      <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">,</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="s2">&quot;Short Wait&quot;</span><span class="p">}],</span> <span class="mf">0.025</span><span class="p">))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>
+<span class="go">                    &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>
+<span class="go">                       &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>
+<span class="go">                       &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>
+<span class="go">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.01, &#39;id&#39;: &#39;Short Wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+<span class="go">         &#39;id&#39;: &#39;Short Wait&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>
+<span class="go">         &#39;id&#39;: &#39;Long Wait&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="GenericWait.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">True</span>
+
+        
+    </div>
+    <a class="headerlink" href="#GenericWait.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for GenericWait plugin configuration.</p>
+
+<p>There are no required or optional configuration keys.</p>
+</div>
+
+
+                            </div>
+                            <div id="GenericWait.process_conf" class="classattr">
+                                        <input id="GenericWait.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="GenericWait.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#GenericWait.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="GenericWait.process_conf-156"><a href="#GenericWait.process_conf-156"><span class="linenos">156</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="GenericWait.process_conf-157"><a href="#GenericWait.process_conf-157"><span class="linenos">157</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="GenericWait.process_conf-158"><a href="#GenericWait.process_conf-158"><span class="linenos">158</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="GenericWait.process_conf-159"><a href="#GenericWait.process_conf-159"><span class="linenos">159</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="GenericWait.process_conf-160"><a href="#GenericWait.process_conf-160"><span class="linenos">160</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="GenericWait.process_conf-161"><a href="#GenericWait.process_conf-161"><span class="linenos">161</span></a>            <span class="s2">&quot;GenericWait&quot;</span><span class="p">,</span>
+</span><span id="GenericWait.process_conf-162"><a href="#GenericWait.process_conf-162"><span class="linenos">162</span></a>            <span class="p">[</span>
+</span><span id="GenericWait.process_conf-163"><a href="#GenericWait.process_conf-163"><span class="linenos">163</span></a>                <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="GenericWait.process_conf-164"><a href="#GenericWait.process_conf-164"><span class="linenos">164</span></a>                    <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">},</span> <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">}}</span>
+</span><span id="GenericWait.process_conf-165"><a href="#GenericWait.process_conf-165"><span class="linenos">165</span></a>                <span class="p">)</span>
+</span><span id="GenericWait.process_conf-166"><a href="#GenericWait.process_conf-166"><span class="linenos">166</span></a>            <span class="p">],</span>
+</span><span id="GenericWait.process_conf-167"><a href="#GenericWait.process_conf-167"><span class="linenos">167</span></a>            <span class="p">[</span>
+</span><span id="GenericWait.process_conf-168"><a href="#GenericWait.process_conf-168"><span class="linenos">168</span></a>                <span class="p">(</span>
+</span><span id="GenericWait.process_conf-169"><a href="#GenericWait.process_conf-169"><span class="linenos">169</span></a>                    <span class="p">[</span>
+</span><span id="GenericWait.process_conf-170"><a href="#GenericWait.process_conf-170"><span class="linenos">170</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="GenericWait.process_conf-171"><a href="#GenericWait.process_conf-171"><span class="linenos">171</span></a>                            <span class="p">{</span>
+</span><span id="GenericWait.process_conf-172"><a href="#GenericWait.process_conf-172"><span class="linenos">172</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="GenericWait.process_conf-173"><a href="#GenericWait.process_conf-173"><span class="linenos">173</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;wait&quot;</span><span class="p">},</span>
+</span><span id="GenericWait.process_conf-174"><a href="#GenericWait.process_conf-174"><span class="linenos">174</span></a>                                <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">},</span>
+</span><span id="GenericWait.process_conf-175"><a href="#GenericWait.process_conf-175"><span class="linenos">175</span></a>                                <span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;string&quot;</span><span class="p">},</span>
+</span><span id="GenericWait.process_conf-176"><a href="#GenericWait.process_conf-176"><span class="linenos">176</span></a>                            <span class="p">}</span>
+</span><span id="GenericWait.process_conf-177"><a href="#GenericWait.process_conf-177"><span class="linenos">177</span></a>                        <span class="p">)</span>
+</span><span id="GenericWait.process_conf-178"><a href="#GenericWait.process_conf-178"><span class="linenos">178</span></a>                    <span class="p">],</span>
+</span><span id="GenericWait.process_conf-179"><a href="#GenericWait.process_conf-179"><span class="linenos">179</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_wait</span><span class="p">,</span>
+</span><span id="GenericWait.process_conf-180"><a href="#GenericWait.process_conf-180"><span class="linenos">180</span></a>                <span class="p">)</span>
+</span><span id="GenericWait.process_conf-181"><a href="#GenericWait.process_conf-181"><span class="linenos">181</span></a>            <span class="p">],</span>
+</span><span id="GenericWait.process_conf-182"><a href="#GenericWait.process_conf-182"><span class="linenos">182</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="GenericWait.run" class="classattr">
+                                        <input id="GenericWait.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="GenericWait.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#GenericWait.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="GenericWait.run-199"><a href="#GenericWait.run-199"><span class="linenos">199</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="GenericWait.run-200"><a href="#GenericWait.run-200"><span class="linenos">200</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="GenericWait.run-201"><a href="#GenericWait.run-201"><span class="linenos">201</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="GenericWait.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="GenericWait.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="GenericWait.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="GenericWait.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Timer">
+                            <input id="Timer-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Timer</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Timer-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Timer"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Timer-204"><a href="#Timer-204"><span class="linenos">204</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Timer</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Timer-205"><a href="#Timer-205"><span class="linenos">205</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Timer that can be started and cancelled.</span>
+</span><span id="Timer-206"><a href="#Timer-206"><span class="linenos">206</span></a>
+</span><span id="Timer-207"><a href="#Timer-207"><span class="linenos">207</span></a><span class="sd">    The &quot;seconds&quot; configuration key gets the number of seconds to wait after</span>
+</span><span id="Timer-208"><a href="#Timer-208"><span class="linenos">208</span></a><span class="sd">    receiving a &quot;start&quot; command before sending the &quot;finished&quot; event.</span>
+</span><span id="Timer-209"><a href="#Timer-209"><span class="linenos">209</span></a><span class="sd">    The &quot;cancel&quot; command cancels all outstanding &quot;finished&quot; events and sends</span>
+</span><span id="Timer-210"><a href="#Timer-210"><span class="linenos">210</span></a><span class="sd">    a corresponding &quot;cancelled&quot; event:</span>
+</span><span id="Timer-211"><a href="#Timer-211"><span class="linenos">211</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Timer-212"><a href="#Timer-212"><span class="linenos">212</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Timer-213"><a href="#Timer-213"><span class="linenos">213</span></a><span class="sd">    ...     {&quot;Timer&quot;: {&quot;plugin&quot;: &quot;Timer&quot;, &quot;seconds&quot;: 0.01}},</span>
+</span><span id="Timer-214"><a href="#Timer-214"><span class="linenos">214</span></a><span class="sd">    ...     [{&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;},</span>
+</span><span id="Timer-215"><a href="#Timer-215"><span class="linenos">215</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;},</span>
+</span><span id="Timer-216"><a href="#Timer-216"><span class="linenos">216</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;cancel&quot;},</span>
+</span><span id="Timer-217"><a href="#Timer-217"><span class="linenos">217</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;},</span>
+</span><span id="Timer-218"><a href="#Timer-218"><span class="linenos">218</span></a><span class="sd">    ...      {&quot;target&quot;: &quot;Timer&quot;, &quot;command&quot;: &quot;start&quot;}], 0.015))</span>
+</span><span id="Timer-219"><a href="#Timer-219"><span class="linenos">219</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Timer-220"><a href="#Timer-220"><span class="linenos">220</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Timer-221"><a href="#Timer-221"><span class="linenos">221</span></a><span class="sd">             &#39;client&#39;: &#39;Timer&#39;, &#39;plugin&#39;: &#39;Timer&#39;,</span>
+</span><span id="Timer-222"><a href="#Timer-222"><span class="linenos">222</span></a><span class="sd">             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}},</span>
+</span><span id="Timer-223"><a href="#Timer-223"><span class="linenos">223</span></a><span class="sd">                       {&#39;event&#39;: {&#39;const&#39;: &#39;cancelled&#39;}}],</span>
+</span><span id="Timer-224"><a href="#Timer-224"><span class="linenos">224</span></a><span class="sd">             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>
+</span><span id="Timer-225"><a href="#Timer-225"><span class="linenos">225</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;start&#39;}},</span>
+</span><span id="Timer-226"><a href="#Timer-226"><span class="linenos">226</span></a><span class="sd">                          {&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>
+</span><span id="Timer-227"><a href="#Timer-227"><span class="linenos">227</span></a><span class="sd">                           &#39;command&#39;: {&#39;const&#39;: &#39;cancel&#39;}}]}</span>
+</span><span id="Timer-228"><a href="#Timer-228"><span class="linenos">228</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="Timer-229"><a href="#Timer-229"><span class="linenos">229</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="Timer-230"><a href="#Timer-230"><span class="linenos">230</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;cancel&#39;}</span>
+</span><span id="Timer-231"><a href="#Timer-231"><span class="linenos">231</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="Timer-232"><a href="#Timer-232"><span class="linenos">232</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;cancelled&#39;, &#39;count&#39;: 2}</span>
+</span><span id="Timer-233"><a href="#Timer-233"><span class="linenos">233</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+</span><span id="Timer-234"><a href="#Timer-234"><span class="linenos">234</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="Timer-235"><a href="#Timer-235"><span class="linenos">235</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</span><span id="Timer-236"><a href="#Timer-236"><span class="linenos">236</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Timer-237"><a href="#Timer-237"><span class="linenos">237</span></a>
+</span><span id="Timer-238"><a href="#Timer-238"><span class="linenos">238</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Timer-239"><a href="#Timer-239"><span class="linenos">239</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">}},</span>
+</span><span id="Timer-240"><a href="#Timer-240"><span class="linenos">240</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">],</span>
+</span><span id="Timer-241"><a href="#Timer-241"><span class="linenos">241</span></a>    <span class="p">}</span>
+</span><span id="Timer-242"><a href="#Timer-242"><span class="linenos">242</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Timer plugin configuration.</span>
+</span><span id="Timer-243"><a href="#Timer-243"><span class="linenos">243</span></a>
+</span><span id="Timer-244"><a href="#Timer-244"><span class="linenos">244</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="Timer-245"><a href="#Timer-245"><span class="linenos">245</span></a>
+</span><span id="Timer-246"><a href="#Timer-246"><span class="linenos">246</span></a><span class="sd">    - &#39;seconds&#39;: number of seconds to wait.</span>
+</span><span id="Timer-247"><a href="#Timer-247"><span class="linenos">247</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Timer-248"><a href="#Timer-248"><span class="linenos">248</span></a>
+</span><span id="Timer-249"><a href="#Timer-249"><span class="linenos">249</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Timer-250"><a href="#Timer-250"><span class="linenos">250</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Timer-251"><a href="#Timer-251"><span class="linenos">251</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="Timer-252"><a href="#Timer-252"><span class="linenos">252</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Timer-253"><a href="#Timer-253"><span class="linenos">253</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Timer-254"><a href="#Timer-254"><span class="linenos">254</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Timer-255"><a href="#Timer-255"><span class="linenos">255</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Timer-256"><a href="#Timer-256"><span class="linenos">256</span></a>            <span class="s2">&quot;Timer&quot;</span><span class="p">,</span>
+</span><span id="Timer-257"><a href="#Timer-257"><span class="linenos">257</span></a>            <span class="p">[</span>
+</span><span id="Timer-258"><a href="#Timer-258"><span class="linenos">258</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}}),</span>
+</span><span id="Timer-259"><a href="#Timer-259"><span class="linenos">259</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;cancelled&quot;</span><span class="p">}}),</span>
+</span><span id="Timer-260"><a href="#Timer-260"><span class="linenos">260</span></a>            <span class="p">],</span>
+</span><span id="Timer-261"><a href="#Timer-261"><span class="linenos">261</span></a>            <span class="p">[</span>
+</span><span id="Timer-262"><a href="#Timer-262"><span class="linenos">262</span></a>                <span class="p">(</span>
+</span><span id="Timer-263"><a href="#Timer-263"><span class="linenos">263</span></a>                    <span class="p">[</span>
+</span><span id="Timer-264"><a href="#Timer-264"><span class="linenos">264</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Timer-265"><a href="#Timer-265"><span class="linenos">265</span></a>                            <span class="p">{</span>
+</span><span id="Timer-266"><a href="#Timer-266"><span class="linenos">266</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Timer-267"><a href="#Timer-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">},</span>
+</span><span id="Timer-268"><a href="#Timer-268"><span class="linenos">268</span></a>                            <span class="p">}</span>
+</span><span id="Timer-269"><a href="#Timer-269"><span class="linenos">269</span></a>                        <span class="p">)</span>
+</span><span id="Timer-270"><a href="#Timer-270"><span class="linenos">270</span></a>                    <span class="p">],</span>
+</span><span id="Timer-271"><a href="#Timer-271"><span class="linenos">271</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_start</span><span class="p">,</span>
+</span><span id="Timer-272"><a href="#Timer-272"><span class="linenos">272</span></a>                <span class="p">),</span>
+</span><span id="Timer-273"><a href="#Timer-273"><span class="linenos">273</span></a>                <span class="p">(</span>
+</span><span id="Timer-274"><a href="#Timer-274"><span class="linenos">274</span></a>                    <span class="p">[</span>
+</span><span id="Timer-275"><a href="#Timer-275"><span class="linenos">275</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Timer-276"><a href="#Timer-276"><span class="linenos">276</span></a>                            <span class="p">{</span>
+</span><span id="Timer-277"><a href="#Timer-277"><span class="linenos">277</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Timer-278"><a href="#Timer-278"><span class="linenos">278</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;cancel&quot;</span><span class="p">},</span>
+</span><span id="Timer-279"><a href="#Timer-279"><span class="linenos">279</span></a>                            <span class="p">}</span>
+</span><span id="Timer-280"><a href="#Timer-280"><span class="linenos">280</span></a>                        <span class="p">)</span>
+</span><span id="Timer-281"><a href="#Timer-281"><span class="linenos">281</span></a>                    <span class="p">],</span>
+</span><span id="Timer-282"><a href="#Timer-282"><span class="linenos">282</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_cancel</span><span class="p">,</span>
+</span><span id="Timer-283"><a href="#Timer-283"><span class="linenos">283</span></a>                <span class="p">),</span>
+</span><span id="Timer-284"><a href="#Timer-284"><span class="linenos">284</span></a>            <span class="p">],</span>
+</span><span id="Timer-285"><a href="#Timer-285"><span class="linenos">285</span></a>        <span class="p">)</span>
+</span><span id="Timer-286"><a href="#Timer-286"><span class="linenos">286</span></a>
+</span><span id="Timer-287"><a href="#Timer-287"><span class="linenos">287</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_start</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Timer-288"><a href="#Timer-288"><span class="linenos">288</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">+=</span> <span class="mi">1</span>
+</span><span id="Timer-289"><a href="#Timer-289"><span class="linenos">289</span></a>
+</span><span id="Timer-290"><a href="#Timer-290"><span class="linenos">290</span></a>        <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">wait_coroutine</span><span class="p">():</span>
+</span><span id="Timer-291"><a href="#Timer-291"><span class="linenos">291</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="Timer-292"><a href="#Timer-292"><span class="linenos">292</span></a>            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+</span><span id="Timer-293"><a href="#Timer-293"><span class="linenos">293</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">-=</span> <span class="mi">1</span>
+</span><span id="Timer-294"><a href="#Timer-294"><span class="linenos">294</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">-=</span> <span class="mi">1</span>
+</span><span id="Timer-295"><a href="#Timer-295"><span class="linenos">295</span></a>            <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+</span><span id="Timer-296"><a href="#Timer-296"><span class="linenos">296</span></a>                <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">-=</span> <span class="mi">1</span>
+</span><span id="Timer-297"><a href="#Timer-297"><span class="linenos">297</span></a>                <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}))</span>
+</span><span id="Timer-298"><a href="#Timer-298"><span class="linenos">298</span></a>
+</span><span id="Timer-299"><a href="#Timer-299"><span class="linenos">299</span></a>        <span class="c1"># Done in separate task to not block queue awaiting this callback:</span>
+</span><span id="Timer-300"><a href="#Timer-300"><span class="linenos">300</span></a>        <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="n">wait_coroutine</span><span class="p">())</span>
+</span><span id="Timer-301"><a href="#Timer-301"><span class="linenos">301</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>
+</span><span id="Timer-302"><a href="#Timer-302"><span class="linenos">302</span></a>        <span class="n">task</span><span class="o">.</span><span class="n">add_done_callback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span><span class="o">.</span><span class="n">discard</span><span class="p">)</span>
+</span><span id="Timer-303"><a href="#Timer-303"><span class="linenos">303</span></a>
+</span><span id="Timer-304"><a href="#Timer-304"><span class="linenos">304</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_cancel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="n">Message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Timer-305"><a href="#Timer-305"><span class="linenos">305</span></a>        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span><span class="p">:</span>
+</span><span id="Timer-306"><a href="#Timer-306"><span class="linenos">306</span></a>            <span class="n">cancel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span>
+</span><span id="Timer-307"><a href="#Timer-307"><span class="linenos">307</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">started</span>
+</span><span id="Timer-308"><a href="#Timer-308"><span class="linenos">308</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span>
+</span><span id="Timer-309"><a href="#Timer-309"><span class="linenos">309</span></a>                <span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;cancelled&quot;</span><span class="p">,</span> <span class="s2">&quot;count&quot;</span><span class="p">:</span> <span class="n">cancel</span><span class="p">})</span>
+</span><span id="Timer-310"><a href="#Timer-310"><span class="linenos">310</span></a>            <span class="p">)</span>
+</span><span id="Timer-311"><a href="#Timer-311"><span class="linenos">311</span></a>
+</span><span id="Timer-312"><a href="#Timer-312"><span class="linenos">312</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Timer-313"><a href="#Timer-313"><span class="linenos">313</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Timer-314"><a href="#Timer-314"><span class="linenos">314</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Timer that can be started and cancelled.</p>
+
+<p>The "seconds" configuration key gets the number of seconds to wait after
+receiving a "start" command before sending the "finished" event.
+The "cancel" command cancels all outstanding "finished" events and sends
+a corresponding "cancelled" event:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Timer&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Timer&quot;</span><span class="p">,</span> <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">}},</span>
+<span class="gp">... </span>    <span class="p">[{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Timer&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Timer&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Timer&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;cancel&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Timer&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">},</span>
+<span class="gp">... </span>     <span class="p">{</span><span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="s2">&quot;Timer&quot;</span><span class="p">,</span> <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">}],</span> <span class="mf">0.015</span><span class="p">))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Timer&#39;, &#39;plugin&#39;: &#39;Timer&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}},</span>
+<span class="go">                   {&#39;event&#39;: {&#39;const&#39;: &#39;cancelled&#39;}}],</span>
+<span class="go">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;start&#39;}},</span>
+<span class="go">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>
+<span class="go">                       &#39;command&#39;: {&#39;const&#39;: &#39;cancel&#39;}}]}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;cancel&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;cancelled&#39;, &#39;count&#39;: 2}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Timer.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<span class="default_value">{&#39;properties&#39;: {&#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;}}, &#39;required&#39;: [&#39;seconds&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Timer.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Timer plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'seconds': number of seconds to wait.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Timer.process_conf" class="classattr">
+                                        <input id="Timer.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Timer.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Timer.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Timer.process_conf-249"><a href="#Timer.process_conf-249"><span class="linenos">249</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Timer.process_conf-250"><a href="#Timer.process_conf-250"><span class="linenos">250</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Timer.process_conf-251"><a href="#Timer.process_conf-251"><span class="linenos">251</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">_tasks</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+</span><span id="Timer.process_conf-252"><a href="#Timer.process_conf-252"><span class="linenos">252</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">started</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Timer.process_conf-253"><a href="#Timer.process_conf-253"><span class="linenos">253</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">cancelled</span> <span class="o">=</span> <span class="mi">0</span>
+</span><span id="Timer.process_conf-254"><a href="#Timer.process_conf-254"><span class="linenos">254</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Timer.process_conf-255"><a href="#Timer.process_conf-255"><span class="linenos">255</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Timer.process_conf-256"><a href="#Timer.process_conf-256"><span class="linenos">256</span></a>            <span class="s2">&quot;Timer&quot;</span><span class="p">,</span>
+</span><span id="Timer.process_conf-257"><a href="#Timer.process_conf-257"><span class="linenos">257</span></a>            <span class="p">[</span>
+</span><span id="Timer.process_conf-258"><a href="#Timer.process_conf-258"><span class="linenos">258</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;finished&quot;</span><span class="p">}}),</span>
+</span><span id="Timer.process_conf-259"><a href="#Timer.process_conf-259"><span class="linenos">259</span></a>                <span class="n">MessageTemplate</span><span class="p">({</span><span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;cancelled&quot;</span><span class="p">}}),</span>
+</span><span id="Timer.process_conf-260"><a href="#Timer.process_conf-260"><span class="linenos">260</span></a>            <span class="p">],</span>
+</span><span id="Timer.process_conf-261"><a href="#Timer.process_conf-261"><span class="linenos">261</span></a>            <span class="p">[</span>
+</span><span id="Timer.process_conf-262"><a href="#Timer.process_conf-262"><span class="linenos">262</span></a>                <span class="p">(</span>
+</span><span id="Timer.process_conf-263"><a href="#Timer.process_conf-263"><span class="linenos">263</span></a>                    <span class="p">[</span>
+</span><span id="Timer.process_conf-264"><a href="#Timer.process_conf-264"><span class="linenos">264</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Timer.process_conf-265"><a href="#Timer.process_conf-265"><span class="linenos">265</span></a>                            <span class="p">{</span>
+</span><span id="Timer.process_conf-266"><a href="#Timer.process_conf-266"><span class="linenos">266</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Timer.process_conf-267"><a href="#Timer.process_conf-267"><span class="linenos">267</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;start&quot;</span><span class="p">},</span>
+</span><span id="Timer.process_conf-268"><a href="#Timer.process_conf-268"><span class="linenos">268</span></a>                            <span class="p">}</span>
+</span><span id="Timer.process_conf-269"><a href="#Timer.process_conf-269"><span class="linenos">269</span></a>                        <span class="p">)</span>
+</span><span id="Timer.process_conf-270"><a href="#Timer.process_conf-270"><span class="linenos">270</span></a>                    <span class="p">],</span>
+</span><span id="Timer.process_conf-271"><a href="#Timer.process_conf-271"><span class="linenos">271</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_start</span><span class="p">,</span>
+</span><span id="Timer.process_conf-272"><a href="#Timer.process_conf-272"><span class="linenos">272</span></a>                <span class="p">),</span>
+</span><span id="Timer.process_conf-273"><a href="#Timer.process_conf-273"><span class="linenos">273</span></a>                <span class="p">(</span>
+</span><span id="Timer.process_conf-274"><a href="#Timer.process_conf-274"><span class="linenos">274</span></a>                    <span class="p">[</span>
+</span><span id="Timer.process_conf-275"><a href="#Timer.process_conf-275"><span class="linenos">275</span></a>                        <span class="n">MessageTemplate</span><span class="p">(</span>
+</span><span id="Timer.process_conf-276"><a href="#Timer.process_conf-276"><span class="linenos">276</span></a>                            <span class="p">{</span>
+</span><span id="Timer.process_conf-277"><a href="#Timer.process_conf-277"><span class="linenos">277</span></a>                                <span class="s2">&quot;target&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">},</span>
+</span><span id="Timer.process_conf-278"><a href="#Timer.process_conf-278"><span class="linenos">278</span></a>                                <span class="s2">&quot;command&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;const&quot;</span><span class="p">:</span> <span class="s2">&quot;cancel&quot;</span><span class="p">},</span>
+</span><span id="Timer.process_conf-279"><a href="#Timer.process_conf-279"><span class="linenos">279</span></a>                            <span class="p">}</span>
+</span><span id="Timer.process_conf-280"><a href="#Timer.process_conf-280"><span class="linenos">280</span></a>                        <span class="p">)</span>
+</span><span id="Timer.process_conf-281"><a href="#Timer.process_conf-281"><span class="linenos">281</span></a>                    <span class="p">],</span>
+</span><span id="Timer.process_conf-282"><a href="#Timer.process_conf-282"><span class="linenos">282</span></a>                    <span class="bp">self</span><span class="o">.</span><span class="n">_cancel</span><span class="p">,</span>
+</span><span id="Timer.process_conf-283"><a href="#Timer.process_conf-283"><span class="linenos">283</span></a>                <span class="p">),</span>
+</span><span id="Timer.process_conf-284"><a href="#Timer.process_conf-284"><span class="linenos">284</span></a>            <span class="p">],</span>
+</span><span id="Timer.process_conf-285"><a href="#Timer.process_conf-285"><span class="linenos">285</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Timer.run" class="classattr">
+                                        <input id="Timer.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Timer.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Timer.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Timer.run-312"><a href="#Timer.run-312"><span class="linenos">312</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Timer.run-313"><a href="#Timer.run-313"><span class="linenos">313</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run no code proactively.&quot;&quot;&quot;</span>
+</span><span id="Timer.run-314"><a href="#Timer.run-314"><span class="linenos">314</span></a>        <span class="k">pass</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run no code proactively.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Timer.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Timer.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Timer.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Timer.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+                <section id="Periodic">
+                            <input id="Periodic-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr class">
+            
+    <span class="def">class</span>
+    <span class="name">Periodic</span><wbr>(<span class="base"><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></span>):
+
+                <label class="view-source-button" for="Periodic-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Periodic"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Periodic-317"><a href="#Periodic-317"><span class="linenos">317</span></a><span class="k">class</span><span class="w"> </span><span class="nc">Periodic</span><span class="p">(</span><span class="n">BasePlugin</span><span class="p">):</span>
+</span><span id="Periodic-318"><a href="#Periodic-318"><span class="linenos">318</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Send message periodically.</span>
+</span><span id="Periodic-319"><a href="#Periodic-319"><span class="linenos">319</span></a>
+</span><span id="Periodic-320"><a href="#Periodic-320"><span class="linenos">320</span></a><span class="sd">    The &quot;seconds&quot; configuration key is the period of the repetition:</span>
+</span><span id="Periodic-321"><a href="#Periodic-321"><span class="linenos">321</span></a><span class="sd">    receiving a &quot;wait&quot; command before sending the &quot;finished&quot; event:</span>
+</span><span id="Periodic-322"><a href="#Periodic-322"><span class="linenos">322</span></a><span class="sd">    &gt;&gt;&gt; import controlpi</span>
+</span><span id="Periodic-323"><a href="#Periodic-323"><span class="linenos">323</span></a><span class="sd">    &gt;&gt;&gt; asyncio.run(controlpi.test(</span>
+</span><span id="Periodic-324"><a href="#Periodic-324"><span class="linenos">324</span></a><span class="sd">    ...     {&quot;Loop&quot;: {&quot;plugin&quot;: &quot;Periodic&quot;, &quot;seconds&quot;: 0.01,</span>
+</span><span id="Periodic-325"><a href="#Periodic-325"><span class="linenos">325</span></a><span class="sd">    ...               &quot;message&quot;: {&quot;key&quot;: &quot;value&quot;}}},</span>
+</span><span id="Periodic-326"><a href="#Periodic-326"><span class="linenos">326</span></a><span class="sd">    ...     [], 0.025))</span>
+</span><span id="Periodic-327"><a href="#Periodic-327"><span class="linenos">327</span></a><span class="sd">    ... # doctest: +NORMALIZE_WHITESPACE</span>
+</span><span id="Periodic-328"><a href="#Periodic-328"><span class="linenos">328</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+</span><span id="Periodic-329"><a href="#Periodic-329"><span class="linenos">329</span></a><span class="sd">             &#39;client&#39;: &#39;Loop&#39;, &#39;plugin&#39;: &#39;Periodic&#39;,</span>
+</span><span id="Periodic-330"><a href="#Periodic-330"><span class="linenos">330</span></a><span class="sd">             &#39;sends&#39;: [{&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}], &#39;receives&#39;: []}</span>
+</span><span id="Periodic-331"><a href="#Periodic-331"><span class="linenos">331</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="Periodic-332"><a href="#Periodic-332"><span class="linenos">332</span></a><span class="sd">    test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</span><span id="Periodic-333"><a href="#Periodic-333"><span class="linenos">333</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Periodic-334"><a href="#Periodic-334"><span class="linenos">334</span></a>
+</span><span id="Periodic-335"><a href="#Periodic-335"><span class="linenos">335</span></a>    <span class="n">CONF_SCHEMA</span> <span class="o">=</span> <span class="p">{</span>
+</span><span id="Periodic-336"><a href="#Periodic-336"><span class="linenos">336</span></a>        <span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;number&quot;</span><span class="p">},</span> <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;object&quot;</span><span class="p">}},</span>
+</span><span id="Periodic-337"><a href="#Periodic-337"><span class="linenos">337</span></a>        <span class="s2">&quot;required&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">,</span> <span class="s2">&quot;message&quot;</span><span class="p">],</span>
+</span><span id="Periodic-338"><a href="#Periodic-338"><span class="linenos">338</span></a>    <span class="p">}</span>
+</span><span id="Periodic-339"><a href="#Periodic-339"><span class="linenos">339</span></a><span class="w">    </span><span class="sd">&quot;&quot;&quot;Schema for Wait plugin configuration.</span>
+</span><span id="Periodic-340"><a href="#Periodic-340"><span class="linenos">340</span></a>
+</span><span id="Periodic-341"><a href="#Periodic-341"><span class="linenos">341</span></a><span class="sd">    Required configuration key:</span>
+</span><span id="Periodic-342"><a href="#Periodic-342"><span class="linenos">342</span></a>
+</span><span id="Periodic-343"><a href="#Periodic-343"><span class="linenos">343</span></a><span class="sd">    - &#39;seconds&#39;: period of repetition in seconds.</span>
+</span><span id="Periodic-344"><a href="#Periodic-344"><span class="linenos">344</span></a><span class="sd">    - &#39;message&#39;: message to send periodically.</span>
+</span><span id="Periodic-345"><a href="#Periodic-345"><span class="linenos">345</span></a><span class="sd">    &quot;&quot;&quot;</span>
+</span><span id="Periodic-346"><a href="#Periodic-346"><span class="linenos">346</span></a>
+</span><span id="Periodic-347"><a href="#Periodic-347"><span class="linenos">347</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Periodic-348"><a href="#Periodic-348"><span class="linenos">348</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Periodic-349"><a href="#Periodic-349"><span class="linenos">349</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Periodic-350"><a href="#Periodic-350"><span class="linenos">350</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Periodic-351"><a href="#Periodic-351"><span class="linenos">351</span></a>            <span class="s2">&quot;Periodic&quot;</span><span class="p">,</span>
+</span><span id="Periodic-352"><a href="#Periodic-352"><span class="linenos">352</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;message&quot;</span><span class="p">])],</span>
+</span><span id="Periodic-353"><a href="#Periodic-353"><span class="linenos">353</span></a>            <span class="p">[],</span>
+</span><span id="Periodic-354"><a href="#Periodic-354"><span class="linenos">354</span></a>        <span class="p">)</span>
+</span><span id="Periodic-355"><a href="#Periodic-355"><span class="linenos">355</span></a>
+</span><span id="Periodic-356"><a href="#Periodic-356"><span class="linenos">356</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Periodic-357"><a href="#Periodic-357"><span class="linenos">357</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run periodic loop.&quot;&quot;&quot;</span>
+</span><span id="Periodic-358"><a href="#Periodic-358"><span class="linenos">358</span></a>        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
+</span><span id="Periodic-359"><a href="#Periodic-359"><span class="linenos">359</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="Periodic-360"><a href="#Periodic-360"><span class="linenos">360</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;message&quot;</span><span class="p">]))</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Send message periodically.</p>
+
+<p>The "seconds" configuration key is the period of the repetition:
+receiving a "wait" command before sending the "finished" event:</p>
+
+<div class="pdoc-code codehilite">
+<pre><span></span><code><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span><span class="w"> </span><span class="nn">controlpi</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n"><a href="../controlpi.html#test">controlpi.test</a></span><span class="p">(</span>
+<span class="gp">... </span>    <span class="p">{</span><span class="s2">&quot;Loop&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;plugin&quot;</span><span class="p">:</span> <span class="s2">&quot;Periodic&quot;</span><span class="p">,</span> <span class="s2">&quot;seconds&quot;</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">,</span>
+<span class="gp">... </span>              <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;value&quot;</span><span class="p">}}},</span>
+<span class="gp">... </span>    <span class="p">[],</span> <span class="mf">0.025</span><span class="p">))</span>
+<span class="gp">... </span><span class="c1"># doctest: +NORMALIZE_WHITESPACE</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>
+<span class="go">         &#39;client&#39;: &#39;Loop&#39;, &#39;plugin&#39;: &#39;Periodic&#39;,</span>
+<span class="go">         &#39;sends&#39;: [{&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}], &#39;receives&#39;: []}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+<span class="go">test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>
+</code></pre>
+</div>
+</div>
+
+
+                            <div id="Periodic.CONF_SCHEMA" class="classattr">
+                                <div class="attr variable">
+            <span class="name">CONF_SCHEMA</span>        =
+<input id="Periodic.CONF_SCHEMA-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+            <label class="view-value-button pdoc-button" for="Periodic.CONF_SCHEMA-view-value"></label><span class="default_value">{&#39;properties&#39;: {&#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;}, &#39;message&#39;: {&#39;type&#39;: &#39;object&#39;}}, &#39;required&#39;: [&#39;seconds&#39;, &#39;message&#39;]}</span>
+
+        
+    </div>
+    <a class="headerlink" href="#Periodic.CONF_SCHEMA"></a>
+    
+            <div class="docstring"><p>Schema for Wait plugin configuration.</p>
+
+<p>Required configuration key:</p>
+
+<ul>
+<li>'seconds': period of repetition in seconds.</li>
+<li>'message': message to send periodically.</li>
+</ul>
+</div>
+
+
+                            </div>
+                            <div id="Periodic.process_conf" class="classattr">
+                                        <input id="Periodic.process_conf-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">def</span>
+        <span class="name">process_conf</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Periodic.process_conf-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Periodic.process_conf"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Periodic.process_conf-347"><a href="#Periodic.process_conf-347"><span class="linenos">347</span></a>    <span class="k">def</span><span class="w"> </span><span class="nf">process_conf</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Periodic.process_conf-348"><a href="#Periodic.process_conf-348"><span class="linenos">348</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Register plugin as bus client.&quot;&quot;&quot;</span>
+</span><span id="Periodic.process_conf-349"><a href="#Periodic.process_conf-349"><span class="linenos">349</span></a>        <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">register</span><span class="p">(</span>
+</span><span id="Periodic.process_conf-350"><a href="#Periodic.process_conf-350"><span class="linenos">350</span></a>            <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
+</span><span id="Periodic.process_conf-351"><a href="#Periodic.process_conf-351"><span class="linenos">351</span></a>            <span class="s2">&quot;Periodic&quot;</span><span class="p">,</span>
+</span><span id="Periodic.process_conf-352"><a href="#Periodic.process_conf-352"><span class="linenos">352</span></a>            <span class="p">[</span><span class="n">MessageTemplate</span><span class="o">.</span><span class="n">from_message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;message&quot;</span><span class="p">])],</span>
+</span><span id="Periodic.process_conf-353"><a href="#Periodic.process_conf-353"><span class="linenos">353</span></a>            <span class="p">[],</span>
+</span><span id="Periodic.process_conf-354"><a href="#Periodic.process_conf-354"><span class="linenos">354</span></a>        <span class="p">)</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Register plugin as bus client.</p>
+</div>
+
+
+                            </div>
+                            <div id="Periodic.run" class="classattr">
+                                        <input id="Periodic.run-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
+<div class="attr function">
+            
+        <span class="def">async def</span>
+        <span class="name">run</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span></span><span class="return-annotation">) -> <span class="kc">None</span>:</span></span>
+
+                <label class="view-source-button" for="Periodic.run-view-source"><span>View Source</span></label>
+
+    </div>
+    <a class="headerlink" href="#Periodic.run"></a>
+            <div class="pdoc-code codehilite"><pre><span></span><span id="Periodic.run-356"><a href="#Periodic.run-356"><span class="linenos">356</span></a>    <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+</span><span id="Periodic.run-357"><a href="#Periodic.run-357"><span class="linenos">357</span></a><span class="w">        </span><span class="sd">&quot;&quot;&quot;Run periodic loop.&quot;&quot;&quot;</span>
+</span><span id="Periodic.run-358"><a href="#Periodic.run-358"><span class="linenos">358</span></a>        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
+</span><span id="Periodic.run-359"><a href="#Periodic.run-359"><span class="linenos">359</span></a>            <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;seconds&quot;</span><span class="p">])</span>
+</span><span id="Periodic.run-360"><a href="#Periodic.run-360"><span class="linenos">360</span></a>            <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">bus</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">Message</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s2">&quot;message&quot;</span><span class="p">]))</span>
+</span></pre></div>
+
+
+            <div class="docstring"><p>Run periodic loop.</p>
+</div>
+
+
+                            </div>
+                            <div class="inherited">
+                                <h5>Inherited Members</h5>
+                                <dl>
+                                    <div><dt><a href="../controlpi/baseplugin.html#BasePlugin">controlpi.baseplugin.BasePlugin</a></dt>
+                                <dd id="Periodic.__init__" class="function"><a href="../controlpi/baseplugin.html#BasePlugin.__init__">BasePlugin</a></dd>
+                <dd id="Periodic.bus" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.bus">bus</a></dd>
+                <dd id="Periodic.name" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.name">name</a></dd>
+                <dd id="Periodic.conf" class="variable"><a href="../controlpi/baseplugin.html#BasePlugin.conf">conf</a></dd>
+
+            </div>
+                                </dl>
+                            </div>
+                </section>
+    </main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "../search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `../${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/index.html b/doc/api/index.html
new file mode 100644 (file)
index 0000000..fdd4c09
--- /dev/null
@@ -0,0 +1,223 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta name="generator" content="pdoc 16.0.0"/>
+    <title>Module List</title>
+
+    <style>/*! * Bootstrap Reboot v5.0.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}</style>
+    <style>/*! syntax-highlighting.css */pre{line-height:125%;}span.linenos{color:inherit; background-color:transparent; padding-left:5px; padding-right:20px;}.pdoc-code .hll{background-color:#ffffcc}.pdoc-code{background:#f8f8f8;}.pdoc-code .c{color:#3D7B7B; font-style:italic}.pdoc-code .err{border:1px solid #FF0000}.pdoc-code .k{color:#008000; font-weight:bold}.pdoc-code .o{color:#666666}.pdoc-code .ch{color:#3D7B7B; font-style:italic}.pdoc-code .cm{color:#3D7B7B; font-style:italic}.pdoc-code .cp{color:#9C6500}.pdoc-code .cpf{color:#3D7B7B; font-style:italic}.pdoc-code .c1{color:#3D7B7B; font-style:italic}.pdoc-code .cs{color:#3D7B7B; font-style:italic}.pdoc-code .gd{color:#A00000}.pdoc-code .ge{font-style:italic}.pdoc-code .gr{color:#E40000}.pdoc-code .gh{color:#000080; font-weight:bold}.pdoc-code .gi{color:#008400}.pdoc-code .go{color:#717171}.pdoc-code .gp{color:#000080; font-weight:bold}.pdoc-code .gs{font-weight:bold}.pdoc-code .gu{color:#800080; font-weight:bold}.pdoc-code .gt{color:#0044DD}.pdoc-code .kc{color:#008000; font-weight:bold}.pdoc-code .kd{color:#008000; font-weight:bold}.pdoc-code .kn{color:#008000; font-weight:bold}.pdoc-code .kp{color:#008000}.pdoc-code .kr{color:#008000; font-weight:bold}.pdoc-code .kt{color:#B00040}.pdoc-code .m{color:#666666}.pdoc-code .s{color:#BA2121}.pdoc-code .na{color:#687822}.pdoc-code .nb{color:#008000}.pdoc-code .nc{color:#0000FF; font-weight:bold}.pdoc-code .no{color:#880000}.pdoc-code .nd{color:#AA22FF}.pdoc-code .ni{color:#717171; font-weight:bold}.pdoc-code .ne{color:#CB3F38; font-weight:bold}.pdoc-code .nf{color:#0000FF}.pdoc-code .nl{color:#767600}.pdoc-code .nn{color:#0000FF; font-weight:bold}.pdoc-code .nt{color:#008000; font-weight:bold}.pdoc-code .nv{color:#19177C}.pdoc-code .ow{color:#AA22FF; font-weight:bold}.pdoc-code .w{color:#bbbbbb}.pdoc-code .mb{color:#666666}.pdoc-code .mf{color:#666666}.pdoc-code .mh{color:#666666}.pdoc-code .mi{color:#666666}.pdoc-code .mo{color:#666666}.pdoc-code .sa{color:#BA2121}.pdoc-code .sb{color:#BA2121}.pdoc-code .sc{color:#BA2121}.pdoc-code .dl{color:#BA2121}.pdoc-code .sd{color:#BA2121; font-style:italic}.pdoc-code .s2{color:#BA2121}.pdoc-code .se{color:#AA5D1F; font-weight:bold}.pdoc-code .sh{color:#BA2121}.pdoc-code .si{color:#A45A77; font-weight:bold}.pdoc-code .sx{color:#008000}.pdoc-code .sr{color:#A45A77}.pdoc-code .s1{color:#BA2121}.pdoc-code .ss{color:#19177C}.pdoc-code .bp{color:#008000}.pdoc-code .fm{color:#0000FF}.pdoc-code .vc{color:#19177C}.pdoc-code .vg{color:#19177C}.pdoc-code .vi{color:#19177C}.pdoc-code .vm{color:#19177C}.pdoc-code .il{color:#666666}</style>
+    <style>/*! theme.css */:root{--pdoc-background:#fff;}.pdoc{--text:#212529;--muted:#6c757d;--link:#3660a5;--link-hover:#1659c5;--code:#f8f8f8;--active:#fff598;--accent:#eee;--accent2:#c1c1c1;--nav-hover:rgba(255, 255, 255, 0.5);--name:#0066BB;--def:#008800;--annotation:#007020;}</style>
+    <style>/*! layout.css */html, body{width:100%;height:100%;}html, main{scroll-behavior:smooth;}body{background-color:var(--pdoc-background);}@media (max-width:769px){#navtoggle{cursor:pointer;position:absolute;width:50px;height:40px;top:1rem;right:1rem;border-color:var(--text);color:var(--text);display:flex;opacity:0.8;z-index:999;}#navtoggle:hover{opacity:1;}#togglestate + div{display:none;}#togglestate:checked + div{display:inherit;}main, header{padding:2rem 3vw;}header + main{margin-top:-3rem;}.git-button{display:none !important;}nav input[type="search"]{max-width:77%;}nav input[type="search"]:first-child{margin-top:-6px;}nav input[type="search"]:valid ~ *{display:none !important;}}@media (min-width:770px){:root{--sidebar-width:clamp(12.5rem, 28vw, 22rem);}nav{position:fixed;overflow:auto;height:100vh;width:var(--sidebar-width);}main, header{padding:3rem 2rem 3rem calc(var(--sidebar-width) + 3rem);width:calc(54rem + var(--sidebar-width));max-width:100%;}header + main{margin-top:-4rem;}#navtoggle{display:none;}}#togglestate{position:absolute;height:0;opacity:0;}nav.pdoc{--pad:clamp(0.5rem, 2vw, 1.75rem);--indent:1.5rem;background-color:var(--accent);border-right:1px solid var(--accent2);box-shadow:0 0 20px rgba(50, 50, 50, .2) inset;padding:0 0 0 var(--pad);overflow-wrap:anywhere;scrollbar-width:thin; scrollbar-color:var(--accent2) transparent; z-index:1}nav.pdoc::-webkit-scrollbar{width:.4rem; }nav.pdoc::-webkit-scrollbar-thumb{background-color:var(--accent2); }nav.pdoc > div{padding:var(--pad) 0;}nav.pdoc .module-list-button{display:inline-flex;align-items:center;color:var(--text);border-color:var(--muted);margin-bottom:1rem;}nav.pdoc .module-list-button:hover{border-color:var(--text);}nav.pdoc input[type=search]{display:block;outline-offset:0;width:calc(100% - var(--pad));}nav.pdoc .logo{max-width:calc(100% - var(--pad));max-height:35vh;display:block;margin:0 auto 1rem;transform:translate(calc(-.5 * var(--pad)), 0);}nav.pdoc ul{list-style:none;padding-left:0;}nav.pdoc > div > ul{margin-left:calc(0px - var(--pad));}nav.pdoc li a{padding:.2rem 0 .2rem calc(var(--pad) + var(--indent));}nav.pdoc > div > ul > li > a{padding-left:var(--pad);}nav.pdoc li{transition:all 100ms;}nav.pdoc li:hover{background-color:var(--nav-hover);}nav.pdoc a, nav.pdoc a:hover{color:var(--text);}nav.pdoc a{display:block;}nav.pdoc > h2:first-of-type{margin-top:1.5rem;}nav.pdoc .class:before{content:"class ";color:var(--muted);}nav.pdoc .function:after{content:"()";color:var(--muted);}nav.pdoc footer:before{content:"";display:block;width:calc(100% - var(--pad));border-top:solid var(--accent2) 1px;margin-top:1.5rem;padding-top:.5rem;}nav.pdoc footer{font-size:small;}</style>
+    <style>/*! content.css */.pdoc{color:var(--text);box-sizing:border-box;line-height:1.5;background:none;}.pdoc .pdoc-button{cursor:pointer;display:inline-block;border:solid black 1px;border-radius:2px;font-size:.75rem;padding:calc(0.5em - 1px) 1em;transition:100ms all;}.pdoc .alert{padding:1rem 1rem 1rem calc(1.5rem + 24px);border:1px solid transparent;border-radius:.25rem;background-repeat:no-repeat;background-position:.75rem center;margin-bottom:1rem;}.pdoc .alert > em{display:none;}.pdoc .alert > *:last-child{margin-bottom:0;}.pdoc .alert.note{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23084298%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%2016A8%208%200%201%200%208%200a8%208%200%200%200%200%2016zm.93-9.412-1%204.705c-.07.34.029.533.304.533.194%200%20.487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703%200-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381%202.29-.287zM8%205.5a1%201%200%201%201%200-2%201%201%200%200%201%200%202z%22/%3E%3C/svg%3E");}.pdoc .alert.tip{color:#0a3622;background-color:#d1e7dd;border-color:#a3cfbb;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%230a3622%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%206a6%206%200%201%201%2010.174%204.31c-.203.196-.359.4-.453.619l-.762%201.769A.5.5%200%200%201%2010.5%2013a.5.5%200%200%201%200%201%20.5.5%200%200%201%200%201l-.224.447a1%201%200%200%201-.894.553H6.618a1%201%200%200%201-.894-.553L5.5%2015a.5.5%200%200%201%200-1%20.5.5%200%200%201%200-1%20.5.5%200%200%201-.46-.302l-.761-1.77a2%202%200%200%200-.453-.618A5.98%205.98%200%200%201%202%206m6-5a5%205%200%200%200-3.479%208.592c.263.254.514.564.676.941L5.83%2012h4.342l.632-1.467c.162-.377.413-.687.676-.941A5%205%200%200%200%208%201%22/%3E%3C/svg%3E");}.pdoc .alert.important{color:#055160;background-color:#cff4fc;border-color:#9eeaf9;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23055160%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%200a2%202%200%200%200-2%202v12a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V2a2%202%200%200%200-2-2zm6%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23664d03%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8.982%201.566a1.13%201.13%200%200%200-1.96%200L.165%2013.233c-.457.778.091%201.767.98%201.767h13.713c.889%200%201.438-.99.98-1.767L8.982%201.566zM8%205c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%205.995A.905.905%200%200%201%208%205zm.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2z%22/%3E%3C/svg%3E");}.pdoc .alert.caution{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M11.46.146A.5.5%200%200%200%2011.107%200H4.893a.5.5%200%200%200-.353.146L.146%204.54A.5.5%200%200%200%200%204.893v6.214a.5.5%200%200%200%20.146.353l4.394%204.394a.5.5%200%200%200%20.353.146h6.214a.5.5%200%200%200%20.353-.146l4.394-4.394a.5.5%200%200%200%20.146-.353V4.893a.5.5%200%200%200-.146-.353zM8%204c.535%200%20.954.462.9.995l-.35%203.507a.552.552%200%200%201-1.1%200L7.1%204.995A.905.905%200%200%201%208%204m.002%206a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E");}.pdoc .alert.danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7;background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22%23842029%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5.52.359A.5.5%200%200%201%206%200h4a.5.5%200%200%201%20.474.658L8.694%206H12.5a.5.5%200%200%201%20.395.807l-7%209a.5.5%200%200%201-.873-.454L6.823%209.5H3.5a.5.5%200%200%201-.48-.641l2.5-8.5z%22/%3E%3C/svg%3E");}.pdoc .visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important;}.pdoc h1, .pdoc h2, .pdoc h3{font-weight:300;margin:.3em 0;padding:.2em 0;}.pdoc > section:not(.module-info) h1{font-size:1.5rem;font-weight:500;}.pdoc > section:not(.module-info) h2{font-size:1.4rem;font-weight:500;}.pdoc > section:not(.module-info) h3{font-size:1.3rem;font-weight:500;}.pdoc > section:not(.module-info) h4{font-size:1.2rem;}.pdoc > section:not(.module-info) h5{font-size:1.1rem;}.pdoc a{text-decoration:none;color:var(--link);}.pdoc a:hover{color:var(--link-hover);}.pdoc blockquote{margin-left:2rem;}.pdoc pre{border-top:1px solid var(--accent2);border-bottom:1px solid var(--accent2);margin-top:0;margin-bottom:1em;padding:.5rem 0 .5rem .5rem;overflow-x:auto;background-color:var(--code);}.pdoc code{color:var(--text);padding:.2em .4em;margin:0;font-size:85%;background-color:var(--accent);border-radius:6px;}.pdoc a > code{color:inherit;}.pdoc pre > code{display:inline-block;font-size:inherit;background:none;border:none;padding:0;}.pdoc > section:not(.module-info){margin-bottom:1.5rem;}.pdoc .modulename{margin-top:0;font-weight:bold;}.pdoc .modulename a{color:var(--link);transition:100ms all;}.pdoc .git-button{float:right;border:solid var(--link) 1px;}.pdoc .git-button:hover{background-color:var(--link);color:var(--pdoc-background);}.view-source-toggle-state,.view-source-toggle-state ~ .pdoc-code{display:none;}.view-source-toggle-state:checked ~ .pdoc-code{display:block;}.view-source-button{display:inline-block;float:right;font-size:.75rem;line-height:1.5rem;color:var(--muted);padding:0 .4rem 0 1.3rem;cursor:pointer;text-indent:-2px;}.view-source-button > span{visibility:hidden;}.module-info .view-source-button{float:none;display:flex;justify-content:flex-end;margin:-1.2rem .4rem -.2rem 0;}.view-source-button::before{position:absolute;content:"View Source";display:list-item;list-style-type:disclosure-closed;}.view-source-toggle-state:checked ~ .attr .view-source-button::before,.view-source-toggle-state:checked ~ .view-source-button::before{list-style-type:disclosure-open;}.pdoc .docstring{margin-bottom:1.5rem;}.pdoc section:not(.module-info) .docstring{margin-left:clamp(0rem, 5vw - 2rem, 1rem);}.pdoc .docstring .pdoc-code{margin-left:1em;margin-right:1em;}.pdoc h1:target,.pdoc h2:target,.pdoc h3:target,.pdoc h4:target,.pdoc h5:target,.pdoc h6:target,.pdoc .pdoc-code > pre > span:target{background-color:var(--active);box-shadow:-1rem 0 0 0 var(--active);}.pdoc .pdoc-code > pre > span:target{display:block;}.pdoc div:target > .attr,.pdoc section:target > .attr,.pdoc dd:target > a{background-color:var(--active);}.pdoc *{scroll-margin:2rem;}.pdoc .pdoc-code .linenos{user-select:none;}.pdoc .attr:hover{filter:contrast(0.95);}.pdoc section, .pdoc .classattr{position:relative;}.pdoc .headerlink{--width:clamp(1rem, 3vw, 2rem);position:absolute;top:0;left:calc(0rem - var(--width));transition:all 100ms ease-in-out;opacity:0;}.pdoc .headerlink::before{content:"#";display:block;text-align:center;width:var(--width);height:2.3rem;line-height:2.3rem;font-size:1.5rem;}.pdoc .attr:hover ~ .headerlink,.pdoc *:target > .headerlink,.pdoc .headerlink:hover{opacity:1;}.pdoc .attr{display:block;margin:.5rem 0 .5rem;padding:.4rem .4rem .4rem 1rem;background-color:var(--accent);overflow-x:auto;}.pdoc .classattr{margin-left:2rem;}.pdoc .decorator-deprecated{color:#842029;}.pdoc .decorator-deprecated ~ span{filter:grayscale(1) opacity(0.8);}.pdoc .name{color:var(--name);font-weight:bold;}.pdoc .def{color:var(--def);font-weight:bold;}.pdoc .signature{background-color:transparent;}.pdoc .param, .pdoc .return-annotation{white-space:pre;}.pdoc .signature.multiline .param{display:block;}.pdoc .signature.condensed .param{display:inline-block;}.pdoc .annotation{color:var(--annotation);}.pdoc .view-value-toggle-state,.pdoc .view-value-toggle-state ~ .default_value{display:none;}.pdoc .view-value-toggle-state:checked ~ .default_value{display:inherit;}.pdoc .view-value-button{font-size:.5rem;vertical-align:middle;border-style:dashed;margin-top:-0.1rem;}.pdoc .view-value-button:hover{background:white;}.pdoc .view-value-button::before{content:"show";text-align:center;width:2.2em;display:inline-block;}.pdoc .view-value-toggle-state:checked ~ .view-value-button::before{content:"hide";}.pdoc .inherited{margin-left:2rem;}.pdoc .inherited dt{font-weight:700;}.pdoc .inherited dt, .pdoc .inherited dd{display:inline;margin-left:0;margin-bottom:.5rem;}.pdoc .inherited dd:not(:last-child):after{content:", ";}.pdoc .inherited .class:before{content:"class ";}.pdoc .inherited .function a:after{content:"()";}.pdoc .search-result .docstring{overflow:auto;max-height:25vh;}.pdoc .search-result.focused > .attr{background-color:var(--active);}.pdoc .attribution{margin-top:2rem;display:block;opacity:0.5;transition:all 200ms;filter:grayscale(100%);}.pdoc .attribution:hover{opacity:1;filter:grayscale(0%);}.pdoc .attribution img{margin-left:5px;height:27px;vertical-align:bottom;width:50px;transition:all 200ms;}.pdoc table{display:block;width:max-content;max-width:100%;overflow:auto;margin-bottom:1rem;}.pdoc table th{font-weight:600;}.pdoc table th, .pdoc table td{padding:6px 13px;border:1px solid var(--accent2);}</style>
+    <style>/*! custom.css */</style>
+    <style>header.pdoc{display:flex;align-items:center;flex-wrap:wrap;}header.pdoc img{max-width:200px;max-height:75px;padding-right:2rem;}header.pdoc input[type=search]{outline-offset:0;font-size:1.5rem;min-width:60%;flex-grow:1;padding-left:.5rem;margin:1.75rem 0;}</style></head>
+<body>
+    <nav class="pdoc">
+        <label id="navtoggle" for="togglestate" class="pdoc-button"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke-linecap='round' stroke="currentColor" stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg></label>
+        <input id="togglestate" type="checkbox" aria-hidden="true" tabindex="-1">
+        <div>    <h2>Available Modules</h2>
+    <ul>
+            <li><a href="controlpi.html">controlpi</a></li>
+            <li><a href="controlpi/baseplugin.html">controlpi.baseplugin</a></li>
+            <li><a href="controlpi/messagebus.html">controlpi.messagebus</a></li>
+            <li><a href="controlpi/pluginregistry.html">controlpi.pluginregistry</a></li>
+            <li><a href="controlpi_plugins.html">controlpi_plugins</a></li>
+            <li><a href="controlpi_plugins/state.html">controlpi_plugins.state</a></li>
+            <li><a href="controlpi_plugins/util.html">controlpi_plugins.util</a></li>
+            <li><a href="controlpi_plugins/wait.html">controlpi_plugins.wait</a></li>
+    </ul>
+</div>
+    </nav>
+    <header class="pdoc">
+                <a href="https://pdoc.dev">
+                    <img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20role%3D%22img%22%20aria-label%3D%22pdoc%20logo%22%20width%3D%22300%22%20height%3D%22160%22%20viewBox%3D%220%200%20150%2080%22%3E%3Ctitle%3Epdoc%3C/title%3E%3Cpath%20d%3D%22M132.316%2048.886c.276-4.679%202.342-6.698%204.409-7.982s4.27-1.165%206.751-1.055c1.586.07%203.044.156%204.222-.482%201.142-.619%202.026-1.932%202.162-3.739.268-3.576-1.929-5.368-5.006-5.551s-7.599.524-10.517%201.606c-4.455%201.652-8.588%206.606-9.552%208.992s-2.342%206.193-1.745%2010.873%202.664%209.221%205.878%2011.79%205.878%203.808%2010.103%204.312%203.444.229%206.062.229%205.006-2.202%204.914-4.909-2.296-5.001-4.501-4.863-3.077.505-5.281.229-7.715-2.064-7.899-9.451z%22%20fill%3D%22%23198754%22/%3E%3Ccircle%20cx%3D%22101.504%22%20cy%3D%2248.943%22%20r%3D%2214.208%22%20fill%3D%22none%22%20stroke%3D%22%23198754%22%20stroke-width%3D%229.354%22/%3E%3Cpath%20d%3D%22M87.81.002c-3.637.065-5.001.454-7.014%201.232s-3.443%201.363-6.3%204.282c-1.723%201.76-3.148%205.019-3.776%207.329-.413%201.521-.316%202.63-.316%202.63l-.195%2034.612c.065%205.774-6.755%208.305-9.612%208.37s-9.678-1.038-9.743-9.408%207.128-9.521%208.362-9.521c1.413-.13%202.526-.021%203.718-.016%202.071.009%204.157-.778%204.092-4.671s-4.157-4.736-4.157-4.736c-6.3-.843-11.43%202.206-11.43%202.206S40.917%2038.15%2041.372%2049.634%2051.568%2068.19%2061.311%2068.125s18.316-7.007%2018.445-17.193l.13-22.772c.046-2.291%202.683-3.644%204.476-4.203.745-.232%201.694-.274%201.694-.274l10.457-.13s4.871-.324%207.729-3.114%204.352-6.294%204.352-6.294.974-3.049.13-4.606-.195-1.233-2.792-3.309-8.573-4.477-8.573-4.477S91.447-.063%2087.81.002zM0%2047.169l.065%2028.417S0%2080.127%204.481%2079.997s5.072-3.866%205.049-4.152l-.113-28.482s1.624-7.656%209.937-7.721%2010.002%206.942%2010.002%208.499-.909%2010.51-9.093%2010.51c-.948%200-2.99-.567-4.145-.272-3.919%201-3.194%204.554-3.194%204.554s.065%205.061%207.404%204.996%2018.575-6.034%2018.575-19.074S26.953%2030.04%2019.549%2029.91%201.234%2035.296%200%2047.169z%22%20fill%3D%22%23198754%22/%3E%3Cg%20transform%3D%22matrix%28.325601%200%200%20.325256%20-10.32669%20-45.802786%29%22%3E%3Ccircle%20cx%3D%22297.554%22%20cy%3D%22172.286%22%20r%3D%2216.5%22%20fill%3D%22%23fff%22/%3E%3Cellipse%20cx%3D%22297.709%22%20cy%3D%22172.642%22%20rx%3D%2211.071%22%20ry%3D%2210.871%22%20fill%3D%22%23105a48%22/%3E%3Ccircle%20cx%3D%22304.104%22%20cy%3D%22167.667%22%20r%3D%224.5%22%20fill%3D%22%23fff%22/%3E%3C/g%3E%3Cpath%20d%3D%22M94.661%2017.032l.893-1.476s.99.714%201.916.925%201.575.114%202.955.114l14.565-.162c1.283-.032%203.085-.762%203.02-3.293s-.373-3.503-.373-3.503l1.283-.487s.52.503.877%201.573.309%201.995.292%202.66-.227%201.541-.227%201.541%201.564-.308%202.359-1.038.823-.779%201.489-1.508.812-.86.812-.86.552-.13.877.26.341.957.065%201.46-1.672%202.206-3.247%203.066-2.76%201.427-3.929%201.768-3.848.73-7.063.714l-10.944-.114s-2.143-.081-3.02-.373-2.241-.973-2.598-1.265z%22%20fill%3D%22%23d36d49%22/%3E%3Cg%20fill%3D%22%23105a48%22%3E%3Cellipse%20cx%3D%2293.052%22%20cy%3D%2243.567%22%20rx%3D%22.869%22%20ry%3D%221.014%22%20transform%3D%22rotate%28341.022%29%22/%3E%3Cellipse%20cx%3D%22104.3%22%20cy%3D%22-16.184%22%20rx%3D%22.865%22%20ry%3D%221.009%22%20transform%3D%22rotate%2814.786%29%22/%3E%3C/g%3E%3C/svg%3E"
+                         alt="pdoc"/>
+                </a>
+            <input type="search" placeholder="Search API Documentation..." aria-label="search box">
+    </header>
+    <main class="pdoc"></main>
+<script>
+    function escapeHTML(html) {
+        return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
+    }
+
+    const originalContent = document.querySelector("main.pdoc");
+    let currentContent = originalContent;
+
+    function setContent(innerHTML) {
+        let elem;
+        if (innerHTML) {
+            elem = document.createElement("main");
+            elem.classList.add("pdoc");
+            elem.innerHTML = innerHTML;
+        } else {
+            elem = originalContent;
+        }
+        if (currentContent !== elem) {
+            currentContent.replaceWith(elem);
+            currentContent = elem;
+        }
+    }
+
+    function getSearchTerm() {
+        return (new URL(window.location)).searchParams.get("search");
+    }
+
+    const searchBox = document.querySelector(".pdoc input[type=search]");
+    searchBox.addEventListener("input", function () {
+        let url = new URL(window.location);
+        if (searchBox.value.trim()) {
+            url.hash = "";
+            url.searchParams.set("search", searchBox.value);
+        } else {
+            url.searchParams.delete("search");
+        }
+        history.replaceState("", "", url.toString());
+        onInput();
+    });
+    window.addEventListener("popstate", onInput);
+
+
+    let search, searchErr;
+
+    async function initialize() {
+        try {
+            search = await new Promise((resolve, reject) => {
+                const script = document.createElement("script");
+                script.type = "text/javascript";
+                script.async = true;
+                script.onload = () => resolve(window.pdocSearch);
+                script.onerror = (e) => reject(e);
+                script.src = "search.js";
+                document.getElementsByTagName("head")[0].appendChild(script);
+            });
+        } catch (e) {
+            console.error("Cannot fetch pdoc search index");
+            searchErr = "Cannot fetch search index.";
+        }
+        onInput();
+
+        document.querySelector("nav.pdoc").addEventListener("click", e => {
+            if (e.target.hash) {
+                searchBox.value = "";
+                searchBox.dispatchEvent(new Event("input"));
+            }
+        });
+    }
+
+    function onInput() {
+        setContent((() => {
+            const term = getSearchTerm();
+            if (!term) {
+                return null
+            }
+            if (searchErr) {
+                return `<h3>Error: ${searchErr}</h3>`
+            }
+            if (!search) {
+                return "<h3>Searching...</h3>"
+            }
+
+            window.scrollTo({top: 0, left: 0, behavior: 'auto'});
+
+            const results = search(term);
+
+            let html;
+            if (results.length === 0) {
+                html = `No search results for '${escapeHTML(term)}'.`
+            } else {
+                html = `<h4>${results.length} search result${results.length > 1 ? "s" : ""} for '${escapeHTML(term)}'.</h4>`;
+            }
+            for (let result of results.slice(0, 10)) {
+                let doc = result.doc;
+                let url = `${doc.modulename.replaceAll(".", "/")}.html`;
+                if (doc.qualname) {
+                    url += `#${doc.qualname}`;
+                }
+
+                let heading;
+                switch (result.doc.kind) {
+                    case "function":
+                        if (doc.fullname.endsWith(".__init__")) {
+                            heading = `<span class="name">${doc.fullname.replace(/\.__init__$/, "")}</span>${doc.signature}`;
+                        } else {
+                            heading = `<span class="def">${doc.funcdef}</span> <span class="name">${doc.fullname}</span>${doc.signature}`;
+                        }
+                        break;
+                    case "class":
+                        heading = `<span class="def">class</span> <span class="name">${doc.fullname}</span>`;
+                        if (doc.bases)
+                            heading += `<wbr>(<span class="base">${doc.bases}</span>)`;
+                        heading += `:`;
+                        break;
+                    case "variable":
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        if (doc.annotation)
+                            heading += `<span class="annotation">${doc.annotation}</span>`;
+                        if (doc.default_value)
+                            heading += `<span class="default_value"> = ${doc.default_value}</span>`;
+                        break;
+                    default:
+                        heading = `<span class="name">${doc.fullname}</span>`;
+                        break;
+                }
+                html += `
+                        <section class="search-result">
+                        <a href="${url}" class="attr ${doc.kind}">${heading}</a>
+                        <div class="docstring">${doc.doc}</div>
+                        </section>
+                    `;
+
+            }
+            return html;
+        })());
+    }
+
+    if (getSearchTerm()) {
+        initialize();
+        searchBox.value = getSearchTerm();
+        onInput();
+    } else {
+        searchBox.addEventListener("focus", initialize, {once: true});
+    }
+
+    searchBox.addEventListener("keydown", e => {
+        if (["ArrowDown", "ArrowUp", "Enter"].includes(e.key)) {
+            let focused = currentContent.querySelector(".search-result.focused");
+            if (!focused) {
+                currentContent.querySelector(".search-result").classList.add("focused");
+            } else if (
+                e.key === "ArrowDown"
+                && focused.nextElementSibling
+                && focused.nextElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.nextElementSibling.classList.add("focused");
+                focused.nextElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "ArrowUp"
+                && focused.previousElementSibling
+                && focused.previousElementSibling.classList.contains("search-result")
+            ) {
+                focused.classList.remove("focused");
+                focused.previousElementSibling.classList.add("focused");
+                focused.previousElementSibling.scrollIntoView({
+                    behavior: "smooth",
+                    block: "nearest",
+                    inline: "nearest"
+                });
+            } else if (
+                e.key === "Enter"
+            ) {
+                focused.querySelector("a").click();
+            }
+        }
+    });
+</script></body>
+</html>
\ No newline at end of file
diff --git a/doc/api/search.js b/doc/api/search.js
new file mode 100644 (file)
index 0000000..96f6b7b
--- /dev/null
@@ -0,0 +1,46 @@
+window.pdocSearch = (function(){
+/** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u<s.length;u++){var a=s[u];r[a]=this.pipeline.run(t.tokenizer(e[a]))}var l={};for(var c in o){var d=r[c]||r.any;if(d){var f=this.fieldSearch(d,c,o),h=o[c].boost;for(var p in f)f[p]=f[p]*h;for(var p in f)p in l?l[p]+=f[p]:l[p]=f[p]}}var v,g=[];for(var p in l)v={ref:p,score:l[p]},this.documentStore.hasDoc(p)&&(v.doc=this.documentStore.getDoc(p)),g.push(v);return g.sort(function(e,t){return t.score-e.score}),g},t.Index.prototype.fieldSearch=function(e,t,n){var i=n[t].bool,o=n[t].expand,r=n[t].boost,s=null,u={};return 0!==r?(e.forEach(function(e){var n=[e];1==o&&(n=this.index[t].expandToken(e));var r={};n.forEach(function(n){var o=this.index[t].getDocs(n),a=this.idf(n,t);if(s&&"AND"==i){var l={};for(var c in s)c in o&&(l[c]=o[c]);o=l}n==e&&this.fieldSearchStats(u,n,o);for(var c in o){var d=this.index[t].getTermFrequency(n,c),f=this.documentStore.getFieldLength(c,t),h=1;0!=f&&(h=1/Math.sqrt(f));var p=1;n!=e&&(p=.15*(1-(n.length-e.length)/n.length));var v=d*a*h*p;c in r?r[c]+=v:r[c]=v}},this),s=this.mergeScores(s,r,i)},this),s=this.coordNorm(s,u,e.length)):void 0},t.Index.prototype.mergeScores=function(e,t,n){if(!e)return t;if("AND"==n){var i={};for(var o in t)o in e&&(i[o]=e[o]+t[o]);return i}for(var o in t)o in e?e[o]+=t[o]:e[o]=t[o];return e},t.Index.prototype.fieldSearchStats=function(e,t,n){for(var i in n)i in e?e[i].push(t):e[i]=[t]},t.Index.prototype.coordNorm=function(e,t,n){for(var i in e)if(i in t){var o=t[i].length;e[i]=e[i]*o/n}return e},t.Index.prototype.toJSON=function(){var e={};return this._fields.forEach(function(t){e[t]=this.index[t].toJSON()},this),{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),index:e,pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(e){var t=Array.prototype.slice.call(arguments,1);t.unshift(this),e.apply(this,t)},t.DocumentStore=function(e){this._save=null===e||void 0===e?!0:e,this.docs={},this.docInfo={},this.length=0},t.DocumentStore.load=function(e){var t=new this;return t.length=e.length,t.docs=e.docs,t.docInfo=e.docInfo,t._save=e.save,t},t.DocumentStore.prototype.isDocStored=function(){return this._save},t.DocumentStore.prototype.addDoc=function(t,n){this.hasDoc(t)||this.length++,this.docs[t]=this._save===!0?e(n):null},t.DocumentStore.prototype.getDoc=function(e){return this.hasDoc(e)===!1?null:this.docs[e]},t.DocumentStore.prototype.hasDoc=function(e){return e in this.docs},t.DocumentStore.prototype.removeDoc=function(e){this.hasDoc(e)&&(delete this.docs[e],delete this.docInfo[e],this.length--)},t.DocumentStore.prototype.addFieldLength=function(e,t,n){null!==e&&void 0!==e&&0!=this.hasDoc(e)&&(this.docInfo[e]||(this.docInfo[e]={}),this.docInfo[e][t]=n)},t.DocumentStore.prototype.updateFieldLength=function(e,t,n){null!==e&&void 0!==e&&0!=this.hasDoc(e)&&this.addFieldLength(e,t,n)},t.DocumentStore.prototype.getFieldLength=function(e,t){return null===e||void 0===e?0:e in this.docs&&t in this.docInfo[e]?this.docInfo[e][t]:0},t.DocumentStore.prototype.toJSON=function(){return{docs:this.docs,docInfo:this.docInfo,length:this.length,save:this._save}},t.stemmer=function(){var e={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},t={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",o=n+"[^aeiouy]*",r=i+"[aeiou]*",s="^("+o+")?"+r+o,u="^("+o+")?"+r+o+"("+r+")?$",a="^("+o+")?"+r+o+r+o,l="^("+o+")?"+i,c=new RegExp(s),d=new RegExp(a),f=new RegExp(u),h=new RegExp(l),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,x=new RegExp("([^aeiouylsz])\\1$"),w=new RegExp("^"+o+i+"[^aeiouwxy]$"),I=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,D=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,_=/^(.+?)e$/,P=/ll$/,k=new RegExp("^"+o+i+"[^aeiouwxy]$"),z=function(n){var i,o,r,s,u,a,l;if(n.length<3)return n;if(r=n.substr(0,1),"y"==r&&(n=r.toUpperCase()+n.substr(1)),s=p,u=v,s.test(n)?n=n.replace(s,"$1$2"):u.test(n)&&(n=n.replace(u,"$1$2")),s=g,u=m,s.test(n)){var z=s.exec(n);s=c,s.test(z[1])&&(s=y,n=n.replace(s,""))}else if(u.test(n)){var z=u.exec(n);i=z[1],u=h,u.test(i)&&(n=i,u=S,a=x,l=w,u.test(n)?n+="e":a.test(n)?(s=y,n=n.replace(s,"")):l.test(n)&&(n+="e"))}if(s=I,s.test(n)){var z=s.exec(n);i=z[1],n=i+"i"}if(s=b,s.test(n)){var z=s.exec(n);i=z[1],o=z[2],s=c,s.test(i)&&(n=i+e[o])}if(s=E,s.test(n)){var z=s.exec(n);i=z[1],o=z[2],s=c,s.test(i)&&(n=i+t[o])}if(s=D,u=F,s.test(n)){var z=s.exec(n);i=z[1],s=d,s.test(i)&&(n=i)}else if(u.test(n)){var z=u.exec(n);i=z[1]+z[2],u=d,u.test(i)&&(n=i)}if(s=_,s.test(n)){var z=s.exec(n);i=z[1],s=d,u=f,a=k,(s.test(i)||u.test(i)&&!a.test(i))&&(n=i)}return s=P,u=d,s.test(n)&&u.test(n)&&(s=y,n=n.replace(s,"")),"y"==r&&(n=r.toLowerCase()+n.substr(1)),n};return z}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.stopWordFilter=function(e){return e&&t.stopWordFilter.stopWords[e]!==!0?e:void 0},t.clearStopWords=function(){t.stopWordFilter.stopWords={}},t.addStopWords=function(e){null!=e&&Array.isArray(e)!==!1&&e.forEach(function(e){t.stopWordFilter.stopWords[e]=!0},this)},t.resetStopWords=function(){t.stopWordFilter.stopWords=t.defaultStopWords},t.defaultStopWords={"":!0,a:!0,able:!0,about:!0,across:!0,after:!0,all:!0,almost:!0,also:!0,am:!0,among:!0,an:!0,and:!0,any:!0,are:!0,as:!0,at:!0,be:!0,because:!0,been:!0,but:!0,by:!0,can:!0,cannot:!0,could:!0,dear:!0,did:!0,"do":!0,does:!0,either:!0,"else":!0,ever:!0,every:!0,"for":!0,from:!0,get:!0,got:!0,had:!0,has:!0,have:!0,he:!0,her:!0,hers:!0,him:!0,his:!0,how:!0,however:!0,i:!0,"if":!0,"in":!0,into:!0,is:!0,it:!0,its:!0,just:!0,least:!0,let:!0,like:!0,likely:!0,may:!0,me:!0,might:!0,most:!0,must:!0,my:!0,neither:!0,no:!0,nor:!0,not:!0,of:!0,off:!0,often:!0,on:!0,only:!0,or:!0,other:!0,our:!0,own:!0,rather:!0,said:!0,say:!0,says:!0,she:!0,should:!0,since:!0,so:!0,some:!0,than:!0,that:!0,the:!0,their:!0,them:!0,then:!0,there:!0,these:!0,they:!0,"this":!0,tis:!0,to:!0,too:!0,twas:!0,us:!0,wants:!0,was:!0,we:!0,were:!0,what:!0,when:!0,where:!0,which:!0,"while":!0,who:!0,whom:!0,why:!0,will:!0,"with":!0,would:!0,yet:!0,you:!0,your:!0},t.stopWordFilter.stopWords=t.defaultStopWords,t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(e){if(null===e||void 0===e)throw new Error("token should not be undefined");return e.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.InvertedIndex=function(){this.root={docs:{},df:0}},t.InvertedIndex.load=function(e){var t=new this;return t.root=e.root,t},t.InvertedIndex.prototype.addToken=function(e,t,n){for(var n=n||this.root,i=0;i<=e.length-1;){var o=e[i];o in n||(n[o]={docs:{},df:0}),i+=1,n=n[o]}var r=t.ref;n.docs[r]?n.docs[r]={tf:t.tf}:(n.docs[r]={tf:t.tf},n.df+=1)},t.InvertedIndex.prototype.hasToken=function(e){if(!e)return!1;for(var t=this.root,n=0;n<e.length;n++){if(!t[e[n]])return!1;t=t[e[n]]}return!0},t.InvertedIndex.prototype.getNode=function(e){if(!e)return null;for(var t=this.root,n=0;n<e.length;n++){if(!t[e[n]])return null;t=t[e[n]]}return t},t.InvertedIndex.prototype.getDocs=function(e){var t=this.getNode(e);return null==t?{}:t.docs},t.InvertedIndex.prototype.getTermFrequency=function(e,t){var n=this.getNode(e);return null==n?0:t in n.docs?n.docs[t].tf:0},t.InvertedIndex.prototype.getDocFreq=function(e){var t=this.getNode(e);return null==t?0:t.df},t.InvertedIndex.prototype.removeToken=function(e,t){if(e){var n=this.getNode(e);null!=n&&t in n.docs&&(delete n.docs[t],n.df-=1)}},t.InvertedIndex.prototype.expandToken=function(e,t,n){if(null==e||""==e)return[];var t=t||[];if(void 0==n&&(n=this.getNode(e),null==n))return t;n.df>0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e<arguments.length;e++)t=arguments[e],~this.indexOf(t)||this.elements.splice(this.locationFor(t),0,t);this.length=this.elements.length},lunr.SortedSet.prototype.toArray=function(){return this.elements.slice()},lunr.SortedSet.prototype.map=function(e,t){return this.elements.map(e,t)},lunr.SortedSet.prototype.forEach=function(e,t){return this.elements.forEach(e,t)},lunr.SortedSet.prototype.indexOf=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]<u[i]?n++:s[n]>u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o<r.length;o++)i.add(r[o]);return i},lunr.SortedSet.prototype.toJSON=function(){return this.toArray()},function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.elasticlunr=t()}(this,function(){return t})}();
+    /** pdoc search index */const docs = {"version": "0.9.5", "fields": ["qualname", "fullname", "annotation", "default_value", "signature", "bases", "doc"], "ref": "fullname", "documentStore": {"docs": {"controlpi": {"fullname": "controlpi", "modulename": "controlpi", "kind": "module", "doc": "<p>Provide the infrastructure for the ControlPi system.</p>\n\n<p>The infrastructure consists of the message bus from module messagebus, the\nplugin registry from module pluginregistry and the abstract base plugin from\nmodule baseplugin.</p>\n\n<p>The package combines them in its run function, which is used by __main__.py\nto run a ControlPi system based on a configuration file indefinitely.</p>\n\n<p>The test function is a utility function to test plugins with minimal\nboilerplate code.</p>\n"}, "controlpi.CONF_SCHEMA": {"fullname": "controlpi.CONF_SCHEMA", "modulename": "controlpi", "qualname": "CONF_SCHEMA", "kind": "variable", "doc": "<p></p>\n", "default_value": "{&#x27;type&#x27;: &#x27;object&#x27;, &#x27;patternProperties&#x27;: {&#x27;.*&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}}}"}, "controlpi.run": {"fullname": "controlpi.run", "modulename": "controlpi", "qualname": "run", "kind": "function", "doc": "<p>Run the ControlPi system based on a configuration.</p>\n\n<p>Setup message bus, process given configuration, and run message bus and\nplugins concurrently and indefinitely.</p>\n\n<p>This function is mainly used by __main__.py to run a ControlPi system\nbased on a configuration loaded from a configuration JSON file on disk.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_coroutine</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">conf</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;Example Init&quot;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>            <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>             <span class=\"s2\">&quot;messages&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                           <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                          <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                           <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Second Message&quot;</span><span class=\"p\">}]},</span>\n<span class=\"gp\">... </span>            <span class=\"s2\">&quot;Example Log&quot;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>            <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Log&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>             <span class=\"s2\">&quot;filter&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;sender&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Example Init&quot;</span><span class=\"p\">}}]}}</span>\n<span class=\"gp\">... </span>    <span class=\"n\">run_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">conf</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.1</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">run_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">run_task</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test_coroutine</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">              &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">              &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"n\">conf</span><span class=\"p\">:</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]]</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi.test": {"fullname": "controlpi.test", "modulename": "controlpi", "qualname": "test", "kind": "function", "doc": "<p>Test configuration of ControlPi system.</p>\n\n<p>Setup message bus, process given configuration, run message bus and\nplugins concurrently, send given messages on message bus and print all\nmessages on message bus. Terminate when queue of message bus is empty.</p>\n\n<p>This function allows to test single plugins or small plugin\nconfigurations with minimal boilerplate code:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Example Init&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                      <span class=\"s2\">&quot;messages&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                    <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                                   <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                    <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Second Message&quot;</span><span class=\"p\">}]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Example Init&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;execute&quot;</span><span class=\"p\">}]))</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Example Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>\n<span class=\"go\">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>\n<span class=\"go\">                   {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>\n<span class=\"go\">                    &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Example Init&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;execute&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Example Init&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>\n</code></pre>\n</div>\n\n<p>Similar functionality could be reached by using the Log and Init plugins\nto print messages and send some messages on the bus, but these would\nclutter the test configuration and code to stop the indefinitely running\nbus would have to be added to each and every test.</p>\n\n<p>Incorrect plugin configurations can also be tested by this:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Example Init&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data must contain [&#39;messages&#39;] properties</span>\n<span class=\"go\">Configuration for &#39;Example Init&#39; is not valid.</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">conf</span><span class=\"p\">:</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]]</span>,</span><span class=\"param\">\t<span class=\"n\">messages</span><span class=\"p\">:</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]]</span>,</span><span class=\"param\">\t<span class=\"n\">wait</span><span class=\"p\">:</span> <span class=\"nb\">float</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi.baseplugin": {"fullname": "controlpi.baseplugin", "modulename": "controlpi.baseplugin", "kind": "module", "doc": "<p>Define base class for all ControlPi plugins.</p>\n\n<p>The class BasePlugin provides the abstract base class for concrete plugins\nrunning on the ControlPi system.</p>\n\n<p>It has three abstract methods that have to be implemented by all concrete\nplugins:</p>\n\n<ul>\n<li>The class property CONF_SCHEMA is the JSON schema of the configuration of\nthe plugin. The configuration read from the global configuration file is\nchecked against this schema during initialisation.</li>\n<li>The method process_conf is called at the end of initialisation and is used\nto initialise the plugin. It can be assumed that self.bus is the message\nbus of the system, self.name the instance name, and self.conf the\nconfiguration already validated against the schema.</li>\n<li>The run coroutines of all plugins are executed concurrently by the main\nsystem.</li>\n</ul>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"n\">CONF_SCHEMA</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                   <span class=\"s1\">&#39;required&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">]}</span>\n<span class=\"gp\">... </span>    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">process_conf</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"k\">if</span> <span class=\"s1\">&#39;key&#39;</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Processing &#39;</span><span class=\"si\">{</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">[</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s2\">&#39;.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Doing something else.&quot;</span><span class=\"p\">)</span>\n</code></pre>\n</div>\n\n<p>Plugins are configured and run based on the information in the global\nconfiguration. Here, we test this manually:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">MessageBus</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;Test Instance&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Something&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">())</span>\n<span class=\"go\">Processing &#39;Something&#39;.</span>\n<span class=\"go\">Doing something else.</span>\n</code></pre>\n</div>\n\n<p>Each plugin gets a reference to the system message bus during\ninitialisation, which can be accessed as self.bus in the functions of the\nplugin class. This can be used to register and unregister message bus\nclients:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">BusPlugin</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"n\">CONF_SCHEMA</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n<span class=\"gp\">... </span>    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">process_conf</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"s1\">&#39;BusPlugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                          <span class=\"p\">[{</span><span class=\"s1\">&#39;event&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}}],</span>\n<span class=\"gp\">... </span>                          <span class=\"p\">[([{</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">}}],</span>\n<span class=\"gp\">... </span>                            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_receive</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">_receive</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"si\">}</span><span class=\"s2\"> received </span><span class=\"si\">{</span><span class=\"n\">message</span><span class=\"si\">}</span><span class=\"s2\">.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"s1\">&#39;event&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Receive&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"s1\">&#39;event&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Run&#39;</span><span class=\"p\">})</span>\n</code></pre>\n</div>\n\n<p>Again, we run this manually here, but this is done by the main coroutine\nwhen using the system in production:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">log</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Log: </span><span class=\"si\">{</span><span class=\"n\">message</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_bus_plugin</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">BusPlugin</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Bus Test&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Test&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;TestPlugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[{}],</span> <span class=\"p\">[([{</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Bus Test&#39;</span><span class=\"p\">}}],</span> <span class=\"n\">log</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"n\">plugin_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Test&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Bus Test&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">gather</span><span class=\"p\">(</span><span class=\"n\">bus_task</span><span class=\"p\">,</span> <span class=\"n\">plugin_task</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test_bus_plugin</span><span class=\"p\">())</span>\n<span class=\"go\">Bus Test received {&#39;sender&#39;: &#39;Test&#39;, &#39;target&#39;: &#39;Bus Test&#39;, &#39;key&#39;: &#39;v&#39;}.</span>\n<span class=\"go\">Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Run&#39;}</span>\n<span class=\"go\">Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Receive&#39;}</span>\n</code></pre>\n</div>\n\n<p>Often, there will be a one-to-one correspondence between plugin\ninstances and message bus clients, a plugin instance will be a message bus\nclient. But there are also cases, where one plugin instance might register\nand unregister a lot of message bus clients, maybe even dynamically through\nits lifetime. A plugin for an input/output card might register separate\nclients for each pin of the card, a plugin for some kind of hardware bus\nmight register separate clients for all devices connected to the bus, or a\nnetwork socket plugin might register separate clients for all connections\nto the socket (and unregister them when the connection is closed).</p>\n"}, "controlpi.baseplugin.JSONSchema": {"fullname": "controlpi.baseplugin.JSONSchema", "modulename": "controlpi.baseplugin", "qualname": "JSONSchema", "kind": "variable", "doc": "<p></p>\n", "default_value": "bool | typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]"}, "controlpi.baseplugin.PluginConf": {"fullname": "controlpi.baseplugin.PluginConf", "modulename": "controlpi.baseplugin", "qualname": "PluginConf", "kind": "variable", "doc": "<p></p>\n", "default_value": "typing.Dict[str, typing.Any]"}, "controlpi.baseplugin.ConfException": {"fullname": "controlpi.baseplugin.ConfException", "modulename": "controlpi.baseplugin", "qualname": "ConfException", "kind": "class", "doc": "<p>Raise for errors in plugin configurations.</p>\n", "bases": "builtins.Exception"}, "controlpi.baseplugin.BasePlugin": {"fullname": "controlpi.baseplugin.BasePlugin", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin", "kind": "class", "doc": "<p>Base class for all ControlPi plugins.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"n\">CONF_SCHEMA</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                   <span class=\"s1\">&#39;required&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">]}</span>\n<span class=\"gp\">... </span>    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">process_conf</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"k\">if</span> <span class=\"s1\">&#39;key&#39;</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Processing &#39;</span><span class=\"si\">{</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">[</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s2\">&#39;.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Doing something else.&quot;</span><span class=\"p\">)</span>\n</code></pre>\n</div>\n\n<p>Initialisation sets the instance variables bus to the given message bus,\nname to the given name, and conf to the given configuration:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"n\">CONF_SCHEMA</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                   <span class=\"s1\">&#39;required&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">]}</span>\n<span class=\"gp\">... </span>    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">process_conf</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"k\">if</span> <span class=\"s1\">&#39;key&#39;</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Processing &#39;</span><span class=\"si\">{</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">[</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s2\">&#39;.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Doing something else.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">MessageBus</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;Test Instance&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Something&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">bus</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">conf</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +ELLIPSIS</span>\n<span class=\"go\">Processing &#39;Something&#39;.</span>\n<span class=\"go\">&lt;controlpi.messagebus.MessageBus object at 0x...&gt;</span>\n<span class=\"go\">Test Instance</span>\n<span class=\"go\">{&#39;key&#39;: &#39;Something&#39;}</span>\n</code></pre>\n</div>\n\n<p>It also validates the configuration against the schema in CONF_SCHEMA\nand raises ConfException if is not validated.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">MessageBus</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;Test Instance&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">baseplugin.ConfException</span>: <span class=\"n\">Configuration for &#39;Test Instance&#39;</span>\n<span class=\"x\">is not valid.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">TestPlugin</span><span class=\"p\">(</span><span class=\"n\">MessageBus</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;Test Instance&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"p\">{</span><span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Something&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">test</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">baseplugin.ConfException</span>: <span class=\"n\">Configuration for &#39;Test Instance&#39;</span>\n<span class=\"x\">is not valid.</span>\n</code></pre>\n</div>\n\n<p>Finally, it calls process_conf, which is the function that should be\noverridden by concrete plugins.</p>\n", "bases": "abc.ABC"}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"fullname": "controlpi.baseplugin.BasePlugin.CONF_SCHEMA", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin.CONF_SCHEMA", "kind": "variable", "doc": "<p></p>\n", "annotation": ": bool | Dict[str, None | str | int | float | bool | Dict[str, Any] | List[Any]]", "default_value": "False"}, "controlpi.baseplugin.BasePlugin.bus": {"fullname": "controlpi.baseplugin.BasePlugin.bus", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin.bus", "kind": "variable", "doc": "<p></p>\n"}, "controlpi.baseplugin.BasePlugin.name": {"fullname": "controlpi.baseplugin.BasePlugin.name", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin.name", "kind": "variable", "doc": "<p></p>\n"}, "controlpi.baseplugin.BasePlugin.conf": {"fullname": "controlpi.baseplugin.BasePlugin.conf", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin.conf", "kind": "variable", "doc": "<p></p>\n"}, "controlpi.baseplugin.BasePlugin.process_conf": {"fullname": "controlpi.baseplugin.BasePlugin.process_conf", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin.process_conf", "kind": "function", "doc": "<p>Process the configuration.</p>\n\n<p>Abstract method has to be overridden by concrete plugins.\nprocess_conf is called at the end of initialisation after the bus\nand the configuration are available as self.bus and self.conf, but\nbefore any of the run coroutines are executed.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.baseplugin.BasePlugin.run": {"fullname": "controlpi.baseplugin.BasePlugin.run", "modulename": "controlpi.baseplugin", "qualname": "BasePlugin.run", "kind": "function", "doc": "<p>Run the plugin.</p>\n\n<p>The coroutine is run concurrently with the message bus and all\nother plugins. Initial messages and other tasks can be done here.\nIt is also okay to run a plugin-specific infinite loop concurrently\nwith the rest of the system.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi.messagebus": {"fullname": "controlpi.messagebus", "modulename": "controlpi.messagebus", "kind": "module", "doc": "<p>Provide an asynchronous message bus.</p>\n\n<p>A message is a dictionary with string keys and string, integer, float,\nBoolean, dictionary, or list values, where the inner dictionaries again\nhave string keys and these values and the inner lists also have elements of\nthese types. All messages have a special key 'sender' with the name of the\nsending client as string value, which is set by the constructor:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 1&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"p\">[</span><span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;value 2&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>\n</code></pre>\n</div>\n\n<p>A message template is a mapping from string keys to JSON schemas as values.\nA message template matches a message if all keys of the template are\ncontained in the message and the values in the message validate against the\nrespective schemas. An empty mapping therefore matches all messages.</p>\n\n<p>The bus executes asynchronous callbacks for all messages to be received by\na client. We use a simple callback printing the message in all examples:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"n\">receiver</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">receiver</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">message</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">return</span> <span class=\"n\">callback</span>\n</code></pre>\n</div>\n\n<p>Clients can be registered at the bus with a name, lists of message templates\nthey want to use for sending and receiving and a callback function for\nreceiving. An empty list of templates means that the client does not want to\nsend or receive any messages, respectively. A list with an empty template\nmeans that it wants to send arbitrary or receive all messages, respectively:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Logger&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"s1\">&#39;Logger&#39;</span><span class=\"p\">))])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">))])</span>\n</code></pre>\n</div>\n\n<p>While most clients should always use their own name for sending, this is not\nenforced and debugging or management clients could send messages on behalf\nof arbitrary client names.</p>\n\n<p>The name of a client has to be unique and is not allowed to be empty\n(otherwise registration fails).</p>\n\n<p>The empty name is used to refer to the bus itself. The bus sends messages\nfor registrations and deregistrations of clients containing their complete\ninterface of send and receive templates. This can be used to allow dynamic\n(debug) clients to deal with arbitrary configurations of clients. The bus\nalso reacts to 'get clients' command messages by sending the complete\ninformation of all currently registered clients.</p>\n\n<p>Clients can send to the bus with the send function. Each message has to\ndeclare a sender. The send templates of that sender are checked for a\ntemplate matching the message:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">send</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Sending messages.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Test&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">})</span>\n</code></pre>\n</div>\n\n<p>The run function executes the message bus forever. If we want to stop it, we\nhave to explicitly cancel the task:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">setup</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">send</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">bus_task</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">Sending messages.</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>\n<span class=\"go\">Client 1: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>\n</code></pre>\n</div>\n"}, "controlpi.messagebus.MessageValue": {"fullname": "controlpi.messagebus.MessageValue", "modulename": "controlpi.messagebus", "qualname": "MessageValue", "kind": "variable", "doc": "<p></p>\n", "default_value": "None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]"}, "controlpi.messagebus.JSONSchema": {"fullname": "controlpi.messagebus.JSONSchema", "modulename": "controlpi.messagebus", "qualname": "JSONSchema", "kind": "variable", "doc": "<p></p>\n", "default_value": "bool | typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]"}, "controlpi.messagebus.MessageCallback": {"fullname": "controlpi.messagebus.MessageCallback", "modulename": "controlpi.messagebus", "qualname": "MessageCallback", "kind": "variable", "doc": "<p></p>\n", "default_value": "typing.Callable[[ForwardRef(&#x27;Message&#x27;)], typing.Coroutine[typing.Any, typing.Any, NoneType]]"}, "controlpi.messagebus.register_schema": {"fullname": "controlpi.messagebus.register_schema", "modulename": "controlpi.messagebus", "qualname": "register_schema", "kind": "function", "doc": "<p>Register the given JSON schema in the global cache.</p>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">schema</span><span class=\"p\">:</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]]</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.validate": {"fullname": "controlpi.messagebus.validate", "modulename": "controlpi.messagebus", "qualname": "validate", "kind": "function", "doc": "<p>Validate the given MessageValue against the given JSON schema string.</p>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">schema_string</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">value</span><span class=\"p\">:</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.Message": {"fullname": "controlpi.messagebus.Message", "modulename": "controlpi.messagebus", "qualname": "Message", "kind": "class", "doc": "<p>Define arbitrary message.</p>\n\n<p>Messages are dictionaries with string keys and values that are strings,\nintegers, floats, Booleans, dictionaries that recursively have string\nkeys and values of any of these types, or lists with elements that have\nany of these types. These constraints are checked when setting key-value\npairs of the message.</p>\n\n<p>A message has to have a sender, which is set by the constructor:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;}</span>\n</code></pre>\n</div>\n\n<p>A dictionary can be given to the constructor:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>            <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 2&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>\n</code></pre>\n</div>\n\n<p>A 'sender' set in the initial dictionary is overwritten by the explicitly\ngiven sender in the first argument:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>            <span class=\"p\">{</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Original sender&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>\n</code></pre>\n</div>\n\n<p>Or the message can be modified after construction:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 1&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"p\">[</span><span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;value 2&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>\n</code></pre>\n</div>\n\n<p>The 'sender' key can be overwritten, but this should only be done in\nexceptional cases:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"p\">[</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;New sender&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;New sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>\n</code></pre>\n</div>\n", "bases": "typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]"}, "controlpi.messagebus.Message.__init__": {"fullname": "controlpi.messagebus.Message.__init__", "modulename": "controlpi.messagebus", "qualname": "Message.__init__", "kind": "function", "doc": "<p>Initialise message.</p>\n\n<p>Message is initialised with given sender and possibly given\nkey-value pairs:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 1&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">sender</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">init</span><span class=\"p\">:</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]]</span> <span class=\"o\">|</span> <span class=\"kc\">None</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></span>)</span>"}, "controlpi.messagebus.Message.check_value": {"fullname": "controlpi.messagebus.Message.check_value", "modulename": "controlpi.messagebus", "qualname": "Message.check_value", "kind": "function", "doc": "<p>Check recursively if a given value is valid.</p>\n\n<p>None, strings, integers, floats and Booleans are valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"s1\">&#39;Spam&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"mi\">42</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"mf\">42.42</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Other basic types are not valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"sa\">b</span><span class=\"s1\">&#39;bytes&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">False</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">)</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>Dictionaries with string keys and recursively valid values are valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">({</span><span class=\"s1\">&#39;str value&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Spam&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;int value&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;float value&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span> <span class=\"s1\">&#39;bool value&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">})</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Empty dictionaries are valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">({})</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Dictionaries with other keys are not valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">({</span><span class=\"mi\">42</span><span class=\"p\">:</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">})</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>Dictionaries with invalid values are not valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">({</span><span class=\"s1\">&#39;complex value&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">})</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>Lists with valid elements are valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">([</span><span class=\"s1\">&#39;Spam&#39;</span><span class=\"p\">,</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">])</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Empty lists are valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">([])</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Lists with invalid elements are not valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Message</span><span class=\"o\">.</span><span class=\"n\">check_value</span><span class=\"p\">([</span><span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">])</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">value</span><span class=\"p\">:</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.Message.update": {"fullname": "controlpi.messagebus.Message.update", "modulename": "controlpi.messagebus", "qualname": "Message.update", "kind": "function", "doc": "<p>Override update to use validity checks.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value 2&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"mi\">42</span><span class=\"p\">:</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;42&#39; is not a valid key in Message (not a string).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"s1\">&#39;complex value&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;1j&#39; is not a valid value in Message.</span>\n</code></pre>\n</div>\n\n<p>This is also used in __init__:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"mi\">42</span><span class=\"p\">:</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;42&#39; is not a valid key in Message (not a string).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;complex value&#39;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;1j&#39; is not a valid value in Message.</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"o\">*</span><span class=\"n\">args</span>, </span><span class=\"param\"><span class=\"o\">**</span><span class=\"n\">kwargs</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.Message.setdefault": {"fullname": "controlpi.messagebus.Message.setdefault", "modulename": "controlpi.messagebus", "qualname": "Message.setdefault", "kind": "function", "doc": "<p>Override setdefault to use validity checks.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example sender&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;value 1&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;value 1&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;value 2&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;value 1&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">)</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;42&#39; is not a valid key in Message (not a string).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;complex value&#39;</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">)</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;1j&#39; is not a valid value in Message.</span>\n</code></pre>\n</div>\n\n<p>But __setitem__ is not called if the key is already present:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"n\">j</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;value 1&#39;</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"bp\">self</span>,</span><span class=\"param\">\t<span class=\"n\">key</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">value</span><span class=\"p\">:</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.MessageTemplate": {"fullname": "controlpi.messagebus.MessageTemplate", "modulename": "controlpi.messagebus", "qualname": "MessageTemplate", "kind": "class", "doc": "<p>Define a message template.</p>\n\n<p>A message template is a mapping from string keys to JSON schemas as\nvalues:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"p\">[</span><span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;object&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>              <span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;number&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                             <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">}}</span>\n</code></pre>\n</div>\n\n<p>A message template matches a message if all keys of the template are\ncontained in the message and the values in the message validate against\nthe respective schemas:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;some string&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">None</span><span class=\"p\">}}))</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>An empty mapping therefore matches all messages:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;arbitrary&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;content&#39;</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n", "bases": "typing.Dict[str, bool | typing.Dict[str, None | str | int | float | bool | typing.Dict[str, typing.Any] | typing.List[typing.Any]]]"}, "controlpi.messagebus.MessageTemplate.__init__": {"fullname": "controlpi.messagebus.MessageTemplate.__init__", "modulename": "controlpi.messagebus", "qualname": "MessageTemplate.__init__", "kind": "function", "doc": "<p>Initialise message.</p>\n\n<p>Template is initialised empty or with given key-value pairs:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n<span class=\"go\">{}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">init</span><span class=\"p\">:</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]]]</span> <span class=\"o\">|</span> <span class=\"kc\">None</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></span>)</span>"}, "controlpi.messagebus.MessageTemplate.from_message": {"fullname": "controlpi.messagebus.MessageTemplate.from_message", "modulename": "controlpi.messagebus", "qualname": "MessageTemplate.from_message", "kind": "function", "doc": "<p>Create template from message.</p>\n\n<p>Template witch constant schemas is created from message:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"o\">.</span><span class=\"n\">from_message</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;dict&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;int&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s1\">&#39;float&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                               <span class=\"s1\">&#39;list&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">]})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"o\">.</span><span class=\"n\">from_message</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">{&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},</span>\n<span class=\"go\"> &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,</span>\n<span class=\"go\">          &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},</span>\n<span class=\"go\">                         &#39;float&#39;: {&#39;const&#39;: 42.42}}},</span>\n<span class=\"go\"> &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,</span>\n<span class=\"go\">          &#39;items&#39;: [{&#39;const&#39;: None},</span>\n<span class=\"go\">                    {&#39;const&#39;: True},</span>\n<span class=\"go\">                    {&#39;const&#39;: &#39;string&#39;}]}}</span>\n</code></pre>\n</div>\n\n<p>This is especially useful for clients that send certain fully\npredefined messages, where the message is given in the configuration\nand the template for the registration can be constructed by this\nmethod.</p>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">MessageTemplate</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.MessageTemplate.update": {"fullname": "controlpi.messagebus.MessageTemplate.update", "modulename": "controlpi.messagebus", "qualname": "MessageTemplate.update", "kind": "function", "doc": "<p>Override update to use validity checks.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;object&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;number&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                                   <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">}}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">{&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>\n<span class=\"go\"> &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>\n<span class=\"go\">           &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>\n<span class=\"go\">                          &#39;key 2&#39;: True}}}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"mi\">42</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">}})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">})</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;schema&#39; is not a valid value in MessageTemplate</span>\n<span class=\"x\">(not a valid JSON schema).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">})</span>\n</code></pre>\n</div>\n\n<p>This is also used in __init__:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;object&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                               <span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n<span class=\"gp\">... </span>                                   <span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;number&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                                   <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">}}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">{&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},</span>\n<span class=\"go\"> &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,</span>\n<span class=\"go\">           &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>\n<span class=\"go\">                          &#39;key 2&#39;: True}}}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"mi\">42</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">}})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;schema&#39; is not a valid value in MessageTemplate</span>\n<span class=\"x\">(not a valid JSON schema).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">})</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"o\">*</span><span class=\"n\">args</span>, </span><span class=\"param\"><span class=\"o\">**</span><span class=\"n\">kwargs</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.MessageTemplate.setdefault": {"fullname": "controlpi.messagebus.MessageTemplate.setdefault", "modulename": "controlpi.messagebus", "qualname": "MessageTemplate.setdefault", "kind": "function", "doc": "<p>Override setdefault to use validity checks.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">})</span>\n<span class=\"go\">{&#39;const&#39;: &#39;value&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">})</span>\n<span class=\"go\">{&#39;type&#39;: &#39;string&#39;}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;object&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                       <span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;number&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                                      <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">}})</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">{&#39;type&#39;: &#39;object&#39;,</span>\n<span class=\"go\">           &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},</span>\n<span class=\"go\">                          &#39;key 2&#39;: True}}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;int key&#39;</span><span class=\"p\">})</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;42&#39; is not a valid key in MessageTemplate (not a string).</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">)</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"gt\">Traceback (most recent call last):</span>\n<span class=\"w\">  </span><span class=\"c\">...</span>\n<span class=\"gr\">TypeError</span>: <span class=\"n\">&#39;schema&#39; is not a valid value in MessageTemplate</span>\n<span class=\"x\">(not a valid JSON schema).</span>\n</code></pre>\n</div>\n\n<p>But __setitem__ is not called if the key is already present:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">setdefault</span><span class=\"p\">(</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;const&#39;: &#39;value&#39;}</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"bp\">self</span>,</span><span class=\"param\">\t<span class=\"n\">key</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">value</span><span class=\"p\">:</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]]</span> <span class=\"o\">|</span> <span class=\"kc\">None</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"kc\">None</span> <span class=\"o\">|</span> <span class=\"nb\">str</span> <span class=\"o\">|</span> <span class=\"nb\">int</span> <span class=\"o\">|</span> <span class=\"nb\">float</span> <span class=\"o\">|</span> <span class=\"nb\">bool</span> <span class=\"o\">|</span> <span class=\"n\">Dict</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">]</span> <span class=\"o\">|</span> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">]]</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.MessageTemplate.check": {"fullname": "controlpi.messagebus.MessageTemplate.check", "modulename": "controlpi.messagebus", "qualname": "MessageTemplate.check", "kind": "function", "doc": "<p>Check message against this template.</p>\n\n<p>Constant values have to match exactly:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;other value&#39;</span><span class=\"p\">}))</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>But for integers, floats with the same value are also valid:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.0</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Type integer is valid for floats with zero fractional part, but\nnot by floats with non-zero fractional part:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.0</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">}))</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>Type number is valid for arbitrary ints or floats:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;number&#39;</span><span class=\"p\">}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">}))</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>All keys in template have to be present in message:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;object&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                               <span class=\"s1\">&#39;properties&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n<span class=\"gp\">... </span>                                   <span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;number&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                                   <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                   <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">}}})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;some string&#39;</span><span class=\"p\">}))</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>But for nested objects their properties do not necessarily have\nto be present:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;some string&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}}))</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Schema True matches everything (even None):</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;some string&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"kc\">None</span><span class=\"p\">}}))</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n\n<p>Schema False matches nothing:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                <span class=\"p\">{</span><span class=\"s1\">&#39;key 1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;key 2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;some string&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key 3&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">}}))</span>\n<span class=\"go\">False</span>\n</code></pre>\n</div>\n\n<p>Message is valid for the constant template created from it:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">m</span> <span class=\"o\">=</span> <span class=\"n\">Message</span><span class=\"p\">(</span><span class=\"s1\">&#39;Example Sender&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;dict&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;int&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s1\">&#39;float&#39;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                               <span class=\"s1\">&#39;list&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">]})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">MessageTemplate</span><span class=\"o\">.</span><span class=\"n\">from_message</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">t</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.TemplateRegistry": {"fullname": "controlpi.messagebus.TemplateRegistry", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry", "kind": "class", "doc": "<p>Manage a collection of message templates with registered clients.</p>\n\n<p>A new TemplateRegistry is created by:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n</code></pre>\n</div>\n\n<p>Client names (strings) can be registered for message templates, which\nare mappings from keys to JSON schemas:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 1&#39;</span><span class=\"p\">)</span>\n</code></pre>\n</div>\n\n<p>The check function checks if the templates registered for a client\nmatch a given message:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 1&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>\n</code></pre>\n</div>\n\n<p>Clients can be registered for values validating against arbitrary JSON\nschemas, e.g. all values of a certain type:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 2&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 2&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 3&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 3&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>\n</code></pre>\n</div>\n\n<p>The order of key-value pairs does not have to match the order in the\nmessages and keys can be left out:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 4&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 4&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>\n</code></pre>\n</div>\n\n<p>A registration for an empty template matches all messages:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({},</span> <span class=\"s1\">&#39;C 5&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 5&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>\n</code></pre>\n</div>\n\n<p>A client can be registered for multiple templates:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 6&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 6&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 6&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>\n</code></pre>\n</div>\n\n<p>Clients can be deregistered again (the result is False if the registry\nis empty after the deletion):</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 7&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">delete</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 7&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 7&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>\n</code></pre>\n</div>\n\n<p>The get function returns all clients with registered templates matching\na given message:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;]</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;, &#39;C 4&#39;]</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 2&#39;, &#39;C 6&#39;]</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 3&#39;, &#39;C 4&#39;]</span>\n</code></pre>\n</div>\n\n<p>The get_templates function returns all templates for a given client:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">c</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;C 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;C 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;C 3&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;C 4&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;C 5&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;C 6&#39;</span><span class=\"p\">]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">c</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"n\">c</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">C 1: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>\n<span class=\"go\">C 2: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>\n<span class=\"go\">C 3: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>\n<span class=\"go\">C 4: [{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>\n<span class=\"go\">C 5: [{}]</span>\n<span class=\"go\">C 6: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>\n</code></pre>\n</div>\n"}, "controlpi.messagebus.TemplateRegistry.__init__": {"fullname": "controlpi.messagebus.TemplateRegistry.__init__", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.__init__", "kind": "function", "doc": "<p>Initialise an empty registry.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">()</span>"}, "controlpi.messagebus.TemplateRegistry.insert": {"fullname": "controlpi.messagebus.TemplateRegistry.insert", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.insert", "kind": "function", "doc": "<p>Register a client for a template.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 1&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 2&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 3&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 4&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({},</span> <span class=\"s1\">&#39;C 5&#39;</span><span class=\"p\">)</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"bp\">self</span>,</span><span class=\"param\">\t<span class=\"n\">template</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">MessageTemplate</span>,</span><span class=\"param\">\t<span class=\"n\">client</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">callback</span><span class=\"p\">:</span> <span class=\"n\">Callable</span><span class=\"p\">[[</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span><span class=\"p\">],</span> <span class=\"n\">Coroutine</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">NoneType</span><span class=\"p\">]]</span> <span class=\"o\">|</span> <span class=\"kc\">None</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.TemplateRegistry.delete": {"fullname": "controlpi.messagebus.TemplateRegistry.delete", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.delete", "kind": "function", "doc": "<p>Unregister a client from all templates.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 1&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 2&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 3&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">},</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;C 4&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({},</span> <span class=\"s1\">&#39;C 5&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">delete</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 3&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">delete</span><span class=\"p\">(</span><span class=\"s1\">&#39;C 4&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">client</span><span class=\"p\">:</span> <span class=\"nb\">str</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.TemplateRegistry.check": {"fullname": "controlpi.messagebus.TemplateRegistry.check", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.check", "kind": "function", "doc": "<p>Get if a client has a registered template matching a message.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">check</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">client</span><span class=\"p\">:</span> <span class=\"nb\">str</span>, </span><span class=\"param\"><span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"nb\">bool</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.TemplateRegistry.get": {"fullname": "controlpi.messagebus.TemplateRegistry.get", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.get", "kind": "function", "doc": "<p>Get all clients registered for templates matching a message.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">m</span> <span class=\"ow\">in</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}]:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">m</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;Client 1&#39;, &#39;Client 2&#39;]</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []</span>\n<span class=\"go\">{&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;Client 2&#39;]</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">]</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"fullname": "controlpi.messagebus.TemplateRegistry.get_callbacks", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.get_callbacks", "kind": "function", "doc": "<p>Get all callbacks registered for templates matching a message.</p>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"bp\">self</span>,</span><span class=\"param\">\t<span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">Callable</span><span class=\"p\">[[</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span><span class=\"p\">],</span> <span class=\"n\">Coroutine</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">NoneType</span><span class=\"p\">]]]</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.TemplateRegistry.get_templates": {"fullname": "controlpi.messagebus.TemplateRegistry.get_templates", "modulename": "controlpi.messagebus", "qualname": "TemplateRegistry.get_templates", "kind": "function", "doc": "<p>Get all templates for a client.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">TemplateRegistry</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v2&#39;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>          <span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;integer&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 3&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 3&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 4&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 4&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[{&#39;k2&#39;: {&#39;const&#39;: 2}}]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({},</span> <span class=\"s1\">&#39;Client 5&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 5&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[{}]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 6&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">insert</span><span class=\"p\">({</span><span class=\"s1\">&#39;k2&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;v1&#39;</span><span class=\"p\">}},</span> <span class=\"s1\">&#39;Client 6&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">get_templates</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 6&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">client</span><span class=\"p\">:</span> <span class=\"nb\">str</span></span><span class=\"return-annotation\">) -> <span class=\"n\">List</span><span class=\"p\">[</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">MessageTemplate</span><span class=\"p\">]</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.BusException": {"fullname": "controlpi.messagebus.BusException", "modulename": "controlpi.messagebus", "qualname": "BusException", "kind": "class", "doc": "<p>Raise for errors in using message bus.</p>\n", "bases": "builtins.Exception"}, "controlpi.messagebus.MessageBus": {"fullname": "controlpi.messagebus.MessageBus", "modulename": "controlpi.messagebus", "qualname": "MessageBus", "kind": "class", "doc": "<p>Provide an asynchronous message bus.</p>\n\n<p>The bus executes asynchronous callbacks for all messages to be received\nby a client. We use a simple callback printing the message in all\nexamples:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"n\">receiver</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Creating callback for </span><span class=\"si\">{</span><span class=\"n\">receiver</span><span class=\"si\">}</span><span class=\"s2\">.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">receiver</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">message</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">return</span> <span class=\"n\">callback</span>\n</code></pre>\n</div>\n\n<p>Clients can be registered at the bus with a name, lists of message\ntemplates they want to use for sending and receiving and a callback\nfunction for receiving. An empty list of templates means that the\nclient does not want to send or receive any messages, respectively.\nA list with an empty template means that it wants to send arbitrary\nor receive all messages, respectively:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Setting up.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Logger&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"s1\">&#39;Logger&#39;</span><span class=\"p\">))])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">))])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback_for_receiver</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">))])</span>\n</code></pre>\n</div>\n\n<p>The bus itself is addressed by the empty string. It sends messages for\neach registration and deregestration of a client with a key 'event' and\na value of 'registered' or 'unregistered', a key 'client' with the\nclient's name as value and for registrations also keys 'sends' and\n'receives' with all templates registered for the client for sending and\nreceiving.</p>\n\n<p>Clients can send to the bus with the send function. Each message has to\ndeclare a sender. The send templates of that sender are checked for a\ntemplate matching the message. We cannot prevent arbitrary code from\nimpersonating any sender, but this should only be done in debugging or\nmanagement situations.</p>\n\n<p>Messages that are intended for a specific client by convention have a\nkey 'target' with the target client's name as value. Such messages are\noften commands to the client to do something, which is by convention\nindicated by a key 'command' with a value that indicates what should be\ndone.</p>\n\n<p>The bus, for example, reacts to a message with 'target': '' and\n'command': 'get clients' by sending one message for each currently\nregistered with complete information about its registered send and\nreceive templates.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">send</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;Sending messages.&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Test&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s1\">&#39;command&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;get clients&#39;</span><span class=\"p\">})</span>\n</code></pre>\n</div>\n\n<p>The run function executes the message bus forever. If we want to stop\nit, we have to explicitly cancel the task:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">setup</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">send</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">bus_task</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">Setting up.</span>\n<span class=\"go\">Creating callback for Logger.</span>\n<span class=\"go\">Creating callback for Client 1.</span>\n<span class=\"go\">Creating callback for Client 2.</span>\n<span class=\"go\">Sending messages.</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>\n<span class=\"go\">Client 1: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;, &#39;command&#39;: &#39;get clients&#39;}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}</span>\n<span class=\"go\">Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}</span>\n</code></pre>\n</div>\n"}, "controlpi.messagebus.MessageBus.__init__": {"fullname": "controlpi.messagebus.MessageBus.__init__", "modulename": "controlpi.messagebus", "qualname": "MessageBus.__init__", "kind": "function", "doc": "<p>Initialise a new bus without clients.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">()</span>"}, "controlpi.messagebus.MessageBus.register": {"fullname": "controlpi.messagebus.MessageBus.register", "modulename": "controlpi.messagebus", "qualname": "MessageBus.register", "kind": "function", "doc": "<p>Register a client at the message bus.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Logger&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[],</span>    <span class=\"c1\"># send nothing</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>  <span class=\"c1\"># receive everything</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                     <span class=\"c1\"># send with key &#39;k1&#39; and string value</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                     <span class=\"c1\"># receive for this client</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>  <span class=\"c1\"># send arbitrary</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                     <span class=\"c1\"># receive for this client</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code multiline\">(<span class=\"param\">\t<span class=\"bp\">self</span>,</span><span class=\"param\">\t<span class=\"n\">client</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">plugin</span><span class=\"p\">:</span> <span class=\"nb\">str</span>,</span><span class=\"param\">\t<span class=\"n\">sends</span><span class=\"p\">:</span> <span class=\"n\">Iterable</span><span class=\"p\">[</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">MessageTemplate</span><span class=\"p\">]</span>,</span><span class=\"param\">\t<span class=\"n\">receives</span><span class=\"p\">:</span> <span class=\"n\">Iterable</span><span class=\"p\">[</span><span class=\"n\">Tuple</span><span class=\"p\">[</span><span class=\"n\">Iterable</span><span class=\"p\">[</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">MessageTemplate</span><span class=\"p\">],</span> <span class=\"n\">Callable</span><span class=\"p\">[[</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span><span class=\"p\">],</span> <span class=\"n\">Coroutine</span><span class=\"p\">[</span><span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">Any</span><span class=\"p\">,</span> <span class=\"n\">NoneType</span><span class=\"p\">]]]]</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.MessageBus.unregister": {"fullname": "controlpi.messagebus.MessageBus.unregister", "modulename": "controlpi.messagebus", "qualname": "MessageBus.unregister", "kind": "function", "doc": "<p>Unregister a client from the message bus.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">unregister</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">client</span><span class=\"p\">:</span> <span class=\"nb\">str</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.messagebus.MessageBus.run": {"fullname": "controlpi.messagebus.MessageBus.run", "modulename": "controlpi.messagebus", "qualname": "MessageBus.run", "kind": "function", "doc": "<p>Run the message bus forever.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">bus_task</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi.messagebus.MessageBus.send": {"fullname": "controlpi.messagebus.MessageBus.send", "modulename": "controlpi.messagebus", "qualname": "MessageBus.send", "kind": "function", "doc": "<p>Send a message to the message bus.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Got: </span><span class=\"si\">{</span><span class=\"n\">message</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Test&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                        <span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">BusException</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">bus_task</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>\n<span class=\"go\">not allowed for sender &#39;Client 1&#39;.</span>\n<span class=\"go\">Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>\n<span class=\"go\">Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi.messagebus.MessageBus.send_nowait": {"fullname": "controlpi.messagebus.MessageBus.send_nowait", "modulename": "controlpi.messagebus", "qualname": "MessageBus.send_nowait", "kind": "function", "doc": "<p>Send a message to the message bus without blocking.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">callback</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;Got: </span><span class=\"si\">{</span><span class=\"n\">message</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">async</span> <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">main</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span> <span class=\"o\">=</span> <span class=\"n\">MessageBus</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;string&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Test Plugin&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({})],</span>\n<span class=\"gp\">... </span>                 <span class=\"p\">[([</span><span class=\"n\">MessageTemplate</span><span class=\"p\">({</span><span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>                                     <span class=\"p\">{</span><span class=\"s1\">&#39;const&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">}})],</span>\n<span class=\"gp\">... </span>                   <span class=\"n\">callback</span><span class=\"p\">)])</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span> <span class=\"o\">=</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">create_task</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">())</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send_nowait</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                     <span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Test&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send_nowait</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"n\">bus</span><span class=\"o\">.</span><span class=\"n\">send_nowait</span><span class=\"p\">({</span><span class=\"s1\">&#39;sender&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 1&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                         <span class=\"s1\">&#39;target&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;Client 2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;k1&#39;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">})</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">BusException</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"k\">await</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"gp\">... </span>    <span class=\"n\">bus_task</span><span class=\"o\">.</span><span class=\"n\">cancel</span><span class=\"p\">()</span>\n<span class=\"gp\">... </span>    <span class=\"k\">try</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">await</span> <span class=\"n\">bus_task</span>\n<span class=\"gp\">... </span>    <span class=\"k\">except</span> <span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">CancelledError</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">main</span><span class=\"p\">())</span>  <span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;</span>\n<span class=\"go\">not allowed for sender &#39;Client 1&#39;.</span>\n<span class=\"go\">Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}</span>\n<span class=\"go\">Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span>, </span><span class=\"param\"><span class=\"n\">message</span><span class=\"p\">:</span> <span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">messagebus</span><span class=\"o\">.</span><span class=\"n\">Message</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi.pluginregistry": {"fullname": "controlpi.pluginregistry", "modulename": "controlpi.pluginregistry", "kind": "module", "doc": "<p>Provide a generic plugin system.</p>\n\n<p>The class PluginRegistry is initialised with the name of a namespace\npackage and a base class.</p>\n\n<p>All modules in the namespace package are loaded. These modules can be\nincluded in different distribution packages, which allows to dynamically\nadd plugins to the system without changing any code.</p>\n\n<p>Afterwards, all (direct and indirect) subclasses of the base class are\nregistered as plugins under their class name. Class names should be unique,\nwhich cannot be programmatically enforced.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">BasePlugin</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Plugin1</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Plugin2</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">registry</span> <span class=\"o\">=</span> <span class=\"n\">PluginRegistry</span><span class=\"p\">(</span><span class=\"s1\">&#39;importlib&#39;</span><span class=\"p\">,</span> <span class=\"n\">BasePlugin</span><span class=\"p\">)</span>\n</code></pre>\n</div>\n\n<p>The registry provides a generic mapping interface with the class names as\nkeys and the classes as values.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">registry</span><span class=\"p\">))</span>\n<span class=\"go\">2</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">name</span> <span class=\"ow\">in</span> <span class=\"n\">registry</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">name</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">registry</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>\n<span class=\"go\">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">if</span> <span class=\"s1\">&#39;Plugin1&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">registry</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;&#39;Plugin1&#39; is in registry.&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;Plugin1&#39; is in registry.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">p1</span> <span class=\"o\">=</span> <span class=\"n\">registry</span><span class=\"p\">[</span><span class=\"s1\">&#39;Plugin1&#39;</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">i1</span> <span class=\"o\">=</span> <span class=\"n\">p1</span><span class=\"p\">()</span>\n</code></pre>\n</div>\n"}, "controlpi.pluginregistry.PluginRegistry": {"fullname": "controlpi.pluginregistry.PluginRegistry", "modulename": "controlpi.pluginregistry", "qualname": "PluginRegistry", "kind": "class", "doc": "<p>Provide a registry for plugins.</p>\n\n<p>Initialise the registry by loading all modules in the given namespace\npackage and then registering all subclasses of the given base class as\nplugins (only simulated here \u2013 the code for Plugin1 and Plugin2 should\nbe in modules in the given namespace package in real applications):</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">BasePlugin</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Plugin1</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Plugin2</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">registry</span> <span class=\"o\">=</span> <span class=\"n\">PluginRegistry</span><span class=\"p\">(</span><span class=\"s1\">&#39;importlib&#39;</span><span class=\"p\">,</span> <span class=\"n\">BasePlugin</span><span class=\"p\">)</span>\n</code></pre>\n</div>\n\n<p>After initialisation, provide a mapping interface to the plugins:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">registry</span><span class=\"p\">))</span>\n<span class=\"go\">2</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">name</span> <span class=\"ow\">in</span> <span class=\"n\">registry</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">name</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">registry</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>\n<span class=\"go\">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">if</span> <span class=\"s1\">&#39;Plugin1&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">registry</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;&#39;Plugin1&#39; is in registry.&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;Plugin1&#39; is in registry.</span>\n</code></pre>\n</div>\n", "bases": "collections.abc.Mapping"}, "controlpi.pluginregistry.PluginRegistry.__init__": {"fullname": "controlpi.pluginregistry.PluginRegistry.__init__", "modulename": "controlpi.pluginregistry", "qualname": "PluginRegistry.__init__", "kind": "function", "doc": "<p>Initialise registry.</p>\n\n<p>Import all modules defined in the given namespace package (in any\ndistribution package currently installed in the path). Then register\nall subclasses of the given base class as plugins.</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">BasePlugin</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Plugin1</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Plugin2</span><span class=\"p\">(</span><span class=\"n\">BasePlugin</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"k\">pass</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">registry</span> <span class=\"o\">=</span> <span class=\"n\">PluginRegistry</span><span class=\"p\">(</span><span class=\"s1\">&#39;importlib&#39;</span><span class=\"p\">,</span> <span class=\"n\">BasePlugin</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">name</span> <span class=\"ow\">in</span> <span class=\"n\">registry</span><span class=\"o\">.</span><span class=\"n\">_plugins</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"sa\">f</span><span class=\"s2\">&quot;</span><span class=\"si\">{</span><span class=\"n\">name</span><span class=\"si\">}</span><span class=\"s2\">: </span><span class=\"si\">{</span><span class=\"n\">registry</span><span class=\"o\">.</span><span class=\"n\">_plugins</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span><span class=\"si\">}</span><span class=\"s2\">&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;</span>\n<span class=\"go\">Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;</span>\n</code></pre>\n</div>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"n\">namespace_package</span><span class=\"p\">:</span> <span class=\"nb\">str</span>, </span><span class=\"param\"><span class=\"n\">base_class</span><span class=\"p\">:</span> <span class=\"nb\">type</span></span>)</span>"}, "controlpi_plugins": {"fullname": "controlpi_plugins", "modulename": "controlpi_plugins", "kind": "module", "doc": "<p></p>\n"}, "controlpi_plugins.state": {"fullname": "controlpi_plugins.state", "modulename": "controlpi_plugins.state", "kind": "module", "doc": "<p>Provide state plugins for all kinds of systems.</p>\n\n<ul>\n<li>State represents a Boolean state.</li>\n<li>StateAlias translates to another state-like client.</li>\n<li>AndState combines several state-like clients by conjunction.</li>\n<li>OrState combines several state-like clients by disjunction.</li>\n<li>AndSet sets a state due to a conjunction of other state-like clients.</li>\n<li>OrSet sets a state due to a disjunction of other state-like clients.</li>\n</ul>\n\n<p>All these plugins use the following conventions:</p>\n\n<ul>\n<li>If their state changes they send a message containing \"event\": \"changed\"\nand \"state\": NEW STATE.</li>\n<li>If their state is reported due to a message, but did not change they send\na message containing just \"state\": CURRENT STATE.</li>\n<li>If they receive a message containing \"target\": NAME and\n\"command\": \"get state\" they report their current state.</li>\n<li>If State (or any other settable state using these conventions) receives\na message containing \"target\": NAME, \"command\": \"set state\" and\n\"new state\": STATE TO SET it changes the state accordingly. If this\nwas really a change the corresponding event is sent. If it was already in\nthis state a report message without \"event\": \"changed\" is sent.</li>\n<li>StateAlias can alias any message bus client using these conventions, not\njust State instances. It translates all messages described here in both\ndirections.</li>\n<li>AndState and OrState instances cannot be set.</li>\n<li>AndState and OrState can combine any message bus clients using these\nconventions, not just State instances. They only react to messages\ncontaining \"state\" information.</li>\n</ul>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 3&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 4&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;StateAlias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                         <span class=\"s2\">&quot;alias for&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test AndState&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;AndState&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                       <span class=\"s2\">&quot;states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">]},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test OrState&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;OrState&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                      <span class=\"s2\">&quot;states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">]},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test AndSet&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;AndSet&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;input states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;output state&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 3&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test OrSet&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;OrSet&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;input states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;output state&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 4&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test AndState&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test OrState&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;, &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;, &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 4&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 4&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n</code></pre>\n</div>\n"}, "controlpi_plugins.state.State": {"fullname": "controlpi_plugins.state.State", "modulename": "controlpi_plugins.state", "qualname": "State", "kind": "class", "doc": "<p>Provide a Boolean state.</p>\n\n<p>The state of a State plugin instance can be queried with the \"get state\"\ncommand and set with the \"set state\" command to the new state given by\nthe \"new state\" key:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.state.State.CONF_SCHEMA": {"fullname": "controlpi_plugins.state.State.CONF_SCHEMA", "modulename": "controlpi_plugins.state", "qualname": "State.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for State plugin configuration.</p>\n\n<p>There are no required or optional configuration keys.</p>\n", "default_value": "True"}, "controlpi_plugins.state.State.process_conf": {"fullname": "controlpi_plugins.state.State.process_conf", "modulename": "controlpi_plugins.state", "qualname": "State.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.state.State.run": {"fullname": "controlpi_plugins.state.State.run", "modulename": "controlpi_plugins.state", "qualname": "State.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.state.StateAlias": {"fullname": "controlpi_plugins.state.StateAlias", "modulename": "controlpi_plugins.state", "qualname": "StateAlias", "kind": "class", "doc": "<p>Define an alias for another state.</p>\n\n<p>The \"alias for\" configuration key gets the name for the other state that\nis aliased by the StateAlias plugin instance.</p>\n\n<p>The \"get state\" and \"set state\" commands are forwarded to and the\n\"changed\" events and \"state\" messages are forwarded from this other\nstate:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;StateAlias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                         <span class=\"s2\">&quot;alias for&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test StateAlias&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"fullname": "controlpi_plugins.state.StateAlias.CONF_SCHEMA", "modulename": "controlpi_plugins.state", "qualname": "StateAlias.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for StateAlias plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'alias for': name of aliased state.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;alias for&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}, &#x27;required&#x27;: [&#x27;alias for&#x27;]}"}, "controlpi_plugins.state.StateAlias.process_conf": {"fullname": "controlpi_plugins.state.StateAlias.process_conf", "modulename": "controlpi_plugins.state", "qualname": "StateAlias.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.state.StateAlias.run": {"fullname": "controlpi_plugins.state.StateAlias.run", "modulename": "controlpi_plugins.state", "qualname": "StateAlias.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.state.AndState": {"fullname": "controlpi_plugins.state.AndState", "modulename": "controlpi_plugins.state", "qualname": "AndState", "kind": "class", "doc": "<p>Define conjunction of states.</p>\n\n<p>The \"states\" configuration key gets an array of states to be combined.\nAn AndState plugin client reacts to \"get state\" commands and sends\n\"changed\" events when a change in one of the combined states leads to\na change for the conjunction:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test AndState&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;AndState&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                       <span class=\"s2\">&quot;states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test AndState&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test AndState&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get sources&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get sources&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndState&#39;,</span>\n<span class=\"go\">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"fullname": "controlpi_plugins.state.AndState.CONF_SCHEMA", "modulename": "controlpi_plugins.state", "qualname": "AndState.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for AndState plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'states': list of names of combined states.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;states&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}}, &#x27;required&#x27;: [&#x27;states&#x27;]}"}, "controlpi_plugins.state.AndState.process_conf": {"fullname": "controlpi_plugins.state.AndState.process_conf", "modulename": "controlpi_plugins.state", "qualname": "AndState.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.state.AndState.run": {"fullname": "controlpi_plugins.state.AndState.run", "modulename": "controlpi_plugins.state", "qualname": "AndState.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.state.OrState": {"fullname": "controlpi_plugins.state.OrState", "modulename": "controlpi_plugins.state", "qualname": "OrState", "kind": "class", "doc": "<p>Define disjunction of states.</p>\n\n<p>The \"states\" configuration key gets an array of states to be combined.\nAn OrState plugin client reacts to \"get state\" commands and sends\n\"changed\" events when a change in one of the combined states leads to\na change for the disjunction:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test OrState&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;OrState&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                      <span class=\"s2\">&quot;states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test OrState&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test OrState&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get sources&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get sources&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrState&#39;,</span>\n<span class=\"go\">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"fullname": "controlpi_plugins.state.OrState.CONF_SCHEMA", "modulename": "controlpi_plugins.state", "qualname": "OrState.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for OrState plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'states': list of names of combined states.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;states&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}}, &#x27;required&#x27;: [&#x27;states&#x27;]}"}, "controlpi_plugins.state.OrState.process_conf": {"fullname": "controlpi_plugins.state.OrState.process_conf", "modulename": "controlpi_plugins.state", "qualname": "OrState.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.state.OrState.run": {"fullname": "controlpi_plugins.state.OrState.run", "modulename": "controlpi_plugins.state", "qualname": "OrState.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.state.AndSet": {"fullname": "controlpi_plugins.state.AndSet", "modulename": "controlpi_plugins.state", "qualname": "AndSet", "kind": "class", "doc": "<p>Set state based on conjunction of other states.</p>\n\n<p>The \"input states\" configuration key gets an array of states used to\ndetermine the state in the \"output state\" configuration key:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 3&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test AndSet&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;AndSet&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;input states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                      <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;output state&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 3&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test AndSet&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test AndSet&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test AndSet&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get sources&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndSet&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get sources&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test AndSet&#39;,</span>\n<span class=\"go\">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"fullname": "controlpi_plugins.state.AndSet.CONF_SCHEMA", "modulename": "controlpi_plugins.state", "qualname": "AndSet.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for AndSet plugin configuration.</p>\n\n<p>Required configuration keys:</p>\n\n<ul>\n<li>'input states': list of names of combined states.</li>\n<li>'output state': name of state to be set.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;input states&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}, &#x27;output state&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}, &#x27;required&#x27;: [&#x27;input states&#x27;, &#x27;output state&#x27;]}"}, "controlpi_plugins.state.AndSet.process_conf": {"fullname": "controlpi_plugins.state.AndSet.process_conf", "modulename": "controlpi_plugins.state", "qualname": "AndSet.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.state.AndSet.run": {"fullname": "controlpi_plugins.state.AndSet.run", "modulename": "controlpi_plugins.state", "qualname": "AndSet.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.state.OrSet": {"fullname": "controlpi_plugins.state.OrSet", "modulename": "controlpi_plugins.state", "qualname": "OrSet", "kind": "class", "doc": "<p>Set state based on disjunction of other states.</p>\n\n<p>The \"input states\" configuration key gets an array of states used to\ndetermine the state in the \"output state\" configuration key:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">asyncio</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test State 3&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;State&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test OrSet&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;OrSet&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;input states&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                      <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>                     <span class=\"s2\">&quot;output state&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 3&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test OrSet&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get state&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 2&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test State 1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set state&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;new state&quot;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test OrSet&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get sources&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;, ...</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get state&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;, &#39;target&#39;: &#39;Test State 3&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 3&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrSet&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get sources&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test OrSet&#39;,</span>\n<span class=\"go\">         &#39;states&#39;: [&#39;Test State 1&#39;, &#39;Test State 2&#39;]}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"fullname": "controlpi_plugins.state.OrSet.CONF_SCHEMA", "modulename": "controlpi_plugins.state", "qualname": "OrSet.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for OrSet plugin configuration.</p>\n\n<p>Required configuration keys:</p>\n\n<ul>\n<li>'input states': list of names of combined states.</li>\n<li>'output state': name of state to be set.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;input states&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}, &#x27;output state&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}, &#x27;required&#x27;: [&#x27;input states&#x27;, &#x27;output state&#x27;]}"}, "controlpi_plugins.state.OrSet.process_conf": {"fullname": "controlpi_plugins.state.OrSet.process_conf", "modulename": "controlpi_plugins.state", "qualname": "OrSet.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.state.OrSet.run": {"fullname": "controlpi_plugins.state.OrSet.run", "modulename": "controlpi_plugins.state", "qualname": "OrSet.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.util": {"fullname": "controlpi_plugins.util", "modulename": "controlpi_plugins.util", "kind": "module", "doc": "<p>Provide utility plugins for all kinds of systems.</p>\n\n<ul>\n<li>Log logs messages on stdout.</li>\n<li>Init sends list of messages on startup and on demand.</li>\n<li>Execute sends configurable list of messages on demand.</li>\n<li>Alias translates messages to an alias.</li>\n</ul>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Log&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Log&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                  <span class=\"s2\">&quot;filter&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;sender&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">}}]},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test Init&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"s2\">&quot;messages&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">}]},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Alias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;from&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;sender&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Init&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                             <span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;translated&quot;</span><span class=\"p\">}}},</span> <span class=\"p\">[]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Alias&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>\n<span class=\"go\">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>\n<span class=\"go\">                       &#39;id&#39;: {&#39;const&#39;: 42}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">Test Log: {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>\n<span class=\"go\">           &#39;content&#39;: &#39;Test Message&#39;}</span>\n</code></pre>\n</div>\n"}, "controlpi_plugins.util.Log": {"fullname": "controlpi_plugins.util.Log", "modulename": "controlpi_plugins.util", "qualname": "Log", "kind": "class", "doc": "<p>Log messages on stdout.</p>\n\n<p>The \"filter\" configuration key gets a list of message templates defining\nthe messages that should be logged by the plugin instance.</p>\n\n<p>In the following example the first and third message match the given\ntemplate and are logged by the instance \"Test Log\", while the second\nmessage does not match and is only logged by the test, but not by the\nLog instance:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Log&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Log&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                  <span class=\"s2\">&quot;filter&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}}]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Second Message&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Third Message&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42.42, &#39;message&#39;: &#39;Second Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>\n<span class=\"go\">Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}</span>\n</code></pre>\n</div>\n\n<p>The \"filter\" key is required:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Log&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Log&quot;</span><span class=\"p\">}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data must contain [&#39;filter&#39;] properties</span>\n<span class=\"go\">Configuration for &#39;Test Log&#39; is not valid.</span>\n</code></pre>\n</div>\n\n<p>The \"filter\" key has to contain a list of message templates, i.e.,\nJSON objects:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Log&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Log&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                  <span class=\"s2\">&quot;filter&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">42</span><span class=\"p\">]}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data.filter[0] must be object</span>\n<span class=\"go\">Configuration for &#39;Test Log&#39; is not valid.</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"fullname": "controlpi_plugins.util.Log.CONF_SCHEMA", "modulename": "controlpi_plugins.util", "qualname": "Log.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Log plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'filter': list of message templates to be logged.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;filter&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}}}, &#x27;required&#x27;: [&#x27;filter&#x27;]}"}, "controlpi_plugins.util.Log.process_conf": {"fullname": "controlpi_plugins.util.Log.process_conf", "modulename": "controlpi_plugins.util", "qualname": "Log.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.util.Log.run": {"fullname": "controlpi_plugins.util.Log.run", "modulename": "controlpi_plugins.util", "qualname": "Log.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.util.Init": {"fullname": "controlpi_plugins.util.Init", "modulename": "controlpi_plugins.util", "qualname": "Init", "kind": "class", "doc": "<p>Send list of messages on startup and on demand.</p>\n\n<p>The \"messages\" configuration key gets a list of messages to be sent on\nstartup. The same list is sent in reaction to a message with\n\"target\": NAME and \"command\": \"execute\".</p>\n\n<p>In the example, the two configured messages are sent twice, once at\nstartup and a second time in reaction to the \"execute\" command sent by\nthe test:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Init&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"s2\">&quot;messages&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                 <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                                <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                                 <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Second Message&quot;</span><span class=\"p\">}]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Init&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;execute&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},</span>\n<span class=\"go\">                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},</span>\n<span class=\"go\">                   {&#39;id&#39;: {&#39;const&#39;: 42.42},</span>\n<span class=\"go\">                    &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Init&#39;, &#39;command&#39;: &#39;execute&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}</span>\n</code></pre>\n</div>\n\n<p>The \"messages\" key is required:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Init&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data must contain [&#39;messages&#39;] properties</span>\n<span class=\"go\">Configuration for &#39;Test Init&#39; is not valid.</span>\n</code></pre>\n</div>\n\n<p>The \"messages\" key has to contain a list of (partial) messages, i.e.,\nJSON objects:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Init&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Init&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"s2\">&quot;messages&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">42</span><span class=\"p\">]}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data.messages[0] must be object</span>\n<span class=\"go\">Configuration for &#39;Test Init&#39; is not valid.</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"fullname": "controlpi_plugins.util.Init.CONF_SCHEMA", "modulename": "controlpi_plugins.util", "qualname": "Init.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Init plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'messages': list of messages to be sent.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;messages&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}}}, &#x27;required&#x27;: [&#x27;messages&#x27;]}"}, "controlpi_plugins.util.Init.process_conf": {"fullname": "controlpi_plugins.util.Init.process_conf", "modulename": "controlpi_plugins.util", "qualname": "Init.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.util.Init.run": {"fullname": "controlpi_plugins.util.Init.run", "modulename": "controlpi_plugins.util", "qualname": "Init.run", "kind": "function", "doc": "<p>Send configured messages on startup.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.util.Execute": {"fullname": "controlpi_plugins.util.Execute", "modulename": "controlpi_plugins.util", "qualname": "Execute", "kind": "class", "doc": "<p>Send configurable list of messages on demand.</p>\n\n<p>An Execute plugin instance receives two kinds of commands.\nThe \"set messages\" command has a \"messages\" key with a list of (partial)\nmessages, which are sent by the Execute instance in reaction to an\n\"execute\" command.</p>\n\n<p>In the example, the first command sent by the test sets two messages,\nwhich are then sent in reaction to the second command sent by the test:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Execute&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Execute&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Execute&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;set messages&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;messages&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                   <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mf\">42.42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Second Message&quot;</span><span class=\"p\">}]},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Execute&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;execute&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Execute&#39;, &#39;plugin&#39;: &#39;Execute&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},</span>\n<span class=\"go\">                       &#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,</span>\n<span class=\"go\">                                    &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},</span>\n<span class=\"go\">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;set messages&#39;,</span>\n<span class=\"go\">         &#39;messages&#39;: [{&#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;},</span>\n<span class=\"go\">                      {&#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;execute&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42.42,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Second Message&#39;}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"fullname": "controlpi_plugins.util.Execute.CONF_SCHEMA", "modulename": "controlpi_plugins.util", "qualname": "Execute.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Execute plugin configuration.</p>\n\n<p>There are no required or optional configuration keys.</p>\n", "default_value": "True"}, "controlpi_plugins.util.Execute.process_conf": {"fullname": "controlpi_plugins.util.Execute.process_conf", "modulename": "controlpi_plugins.util", "qualname": "Execute.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.util.Execute.run": {"fullname": "controlpi_plugins.util.Execute.run", "modulename": "controlpi_plugins.util", "qualname": "Execute.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.util.Alias": {"fullname": "controlpi_plugins.util.Alias", "modulename": "controlpi_plugins.util", "qualname": "Alias", "kind": "class", "doc": "<p>Translate messages to an alias.</p>\n\n<p>The \"from\" configuration key gets a message template and the\nconfiguration key \"to\" a (partial) message. The \"translate\"\nconfiguration key contains pairs of message keys, where the \"from\"\nmessage key is translated to the \"to\" message key if present in the\nmessage.</p>\n\n<p>All messages matching the \"from\" template are received by the Alias\ninstance and a message translated by adding the keys and values of the\n\"to\" message and the translated key-value pairs according to\n\"translate\" is sent. Keys that are not \"sender\" and not modified by\n\"to\" or \"translate\" are retained.</p>\n\n<p>In the example, the two messages sent by the test are translated by the\nAlias instance and the translated messages are sent by it preserving\nthe \"content\" keys:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Alias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;from&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;translated&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;translate&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;from&#39;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;old&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;new&quot;</span><span class=\"p\">}]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;old&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Second Message&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;old&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Second Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>\n</code></pre>\n</div>\n\n<p>An Alias instance can also translate to a list of messages instead of\na single message:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Alias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;from&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;first&quot;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;second&quot;</span><span class=\"p\">}],</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;translate&quot;</span><span class=\"p\">:</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;from&#39;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;old&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;new&quot;</span><span class=\"p\">}]}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Message&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;old&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;content&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;first&#39;}},</span>\n<span class=\"go\">                   {&#39;id&#39;: {&#39;const&#39;: &#39;second&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;first&#39;,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;second&#39;,</span>\n<span class=\"go\">         &#39;content&#39;: &#39;Test Message&#39;, &#39;old&#39;: &#39;content&#39;, &#39;new&#39;: &#39;content&#39;}</span>\n</code></pre>\n</div>\n\n<p>The \"from\" key is required:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Alias&quot;</span><span class=\"p\">}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data must contain [&#39;from&#39;] properties</span>\n<span class=\"go\">Configuration for &#39;Test Alias&#39; is not valid.</span>\n</code></pre>\n</div>\n\n<p>The \"from\" key has to contain a message template and the \"to\" key a\n(partial) message, i.e., both have to be JSON objects:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Alias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;from&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data.from must be object</span>\n<span class=\"go\">Configuration for &#39;Test Alias&#39; is not valid.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Alias&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Alias&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;from&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>                    <span class=\"s2\">&quot;to&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}},</span> <span class=\"p\">[]))</span>\n<span class=\"go\">data.to cannot be validated by any definition</span>\n<span class=\"go\">Configuration for &#39;Test Alias&#39; is not valid.</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"fullname": "controlpi_plugins.util.Alias.CONF_SCHEMA", "modulename": "controlpi_plugins.util", "qualname": "Alias.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Alias plugin configuration.</p>\n\n<p>Required configuration keys:</p>\n\n<ul>\n<li>'from': template of messages to be translated.</li>\n</ul>\n\n<p>Optional configuration keys:</p>\n\n<ul>\n<li>'to': translated message(s) to be sent.</li>\n<li>'translate': array of pairs of keys to be translated.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;from&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}, &#x27;to&#x27;: {&#x27;anyOf&#x27;: [{&#x27;type&#x27;: &#x27;object&#x27;}, {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}}]}, &#x27;translate&#x27;: {&#x27;type&#x27;: &#x27;array&#x27;, &#x27;items&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;, &#x27;properties&#x27;: {&#x27;from&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}, &#x27;to&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;}}}}}, &#x27;required&#x27;: [&#x27;from&#x27;]}"}, "controlpi_plugins.util.Alias.process_conf": {"fullname": "controlpi_plugins.util.Alias.process_conf", "modulename": "controlpi_plugins.util", "qualname": "Alias.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.util.Alias.run": {"fullname": "controlpi_plugins.util.Alias.run", "modulename": "controlpi_plugins.util", "qualname": "Alias.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.util.Counter": {"fullname": "controlpi_plugins.util.Counter", "modulename": "controlpi_plugins.util", "qualname": "Counter", "kind": "class", "doc": "<p>Count messages confirming to a given template.</p>\n\n<p>The plugin counts messages confirming to the given template. The\ncounter can be queried and reset by commands. The 'reset' command also\nqueries the last count before the reset:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Counter&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Counter&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                      <span class=\"s2\">&quot;count&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;const&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}}}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Counter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get count&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">49</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Counter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get count&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Counter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;reset&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Counter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get count&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Counter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get count&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Counter&#39;, &#39;plugin&#39;: &#39;Counter&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;count&#39;: {&#39;type&#39;: &#39;integer&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}},</span>\n<span class=\"go\">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;get count&#39;}},</span>\n<span class=\"go\">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test Counter&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;reset&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get count&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>\n<span class=\"go\">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 49}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get count&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 2,</span>\n<span class=\"go\">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;reset&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get count&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 5,</span>\n<span class=\"go\">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 0,</span>\n<span class=\"go\">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Counter&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get count&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Counter&#39;, &#39;count&#39;: 3,</span>\n<span class=\"go\">         &#39;since&#39;: ..., &#39;until&#39;: ...}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"fullname": "controlpi_plugins.util.Counter.CONF_SCHEMA", "modulename": "controlpi_plugins.util", "qualname": "Counter.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Counter plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'count': template of messages to be counted.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;count&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}, &#x27;date format&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;, &#x27;default&#x27;: &#x27;%Y-%m-%d %H:%M:%S&#x27;}}, &#x27;required&#x27;: [&#x27;count&#x27;]}"}, "controlpi_plugins.util.Counter.process_conf": {"fullname": "controlpi_plugins.util.Counter.process_conf", "modulename": "controlpi_plugins.util", "qualname": "Counter.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.util.Counter.run": {"fullname": "controlpi_plugins.util.Counter.run", "modulename": "controlpi_plugins.util", "qualname": "Counter.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.util.Date": {"fullname": "controlpi_plugins.util.Date", "modulename": "controlpi_plugins.util", "qualname": "Date", "kind": "class", "doc": "<p>Send message with current date.</p>\n\n<p>The plugin reacts to 'get date' commands by sending messages with\na 'date' key:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Date&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Date&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Date&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get date&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get date&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>\n</code></pre>\n</div>\n\n<p>The format of the date can be configured with the 'format'\nconfiguration key:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Date&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Date&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>                   <span class=\"s2\">&quot;format&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;%Y%m</span><span class=\"si\">%d</span><span class=\"s2\">%H%M%S</span><span class=\"si\">%f</span><span class=\"s2\">&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Date&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;get date&quot;</span><span class=\"p\">}]))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE +ELLIPSIS</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Date&#39;, &#39;plugin&#39;: &#39;Date&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;date&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Date&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;get date&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Date&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;get date&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Date&#39;, &#39;date&#39;: ...}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"fullname": "controlpi_plugins.util.Date.CONF_SCHEMA", "modulename": "controlpi_plugins.util", "qualname": "Date.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Date plugin configuration.</p>\n\n<p>Optional configuration key:</p>\n\n<ul>\n<li>'format': format for the sent datetime string.\nDefault: '%Y-%m-%d %H:%M:%S'</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;format&#x27;: {&#x27;type&#x27;: &#x27;string&#x27;, &#x27;default&#x27;: &#x27;%Y-%m-%d %H:%M:%S&#x27;}}}"}, "controlpi_plugins.util.Date.process_conf": {"fullname": "controlpi_plugins.util.Date.process_conf", "modulename": "controlpi_plugins.util", "qualname": "Date.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.util.Date.run": {"fullname": "controlpi_plugins.util.Date.run", "modulename": "controlpi_plugins.util", "qualname": "Date.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.wait": {"fullname": "controlpi_plugins.wait", "modulename": "controlpi_plugins.wait", "kind": "module", "doc": "<p>Provide waiting/sleeping plugins for all kinds of systems.</p>\n\n<ul>\n<li>Wait waits for time defined in configuration and sends \"finished\" event.</li>\n<li>GenericWait waits for time defined in \"wait\" command and sends \"finished\"\nevent with \"id\" string defined in \"wait\" command.</li>\n</ul>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test Wait&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Wait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.01</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Test GenericWait&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;GenericWait&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test GenericWait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;wait&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.02</span><span class=\"p\">,</span> <span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Long Wait&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test Wait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;wait&quot;</span><span class=\"p\">}],</span> <span class=\"mf\">0.025</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Wait&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>\n<span class=\"go\">                    &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>\n<span class=\"go\">                       &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>\n<span class=\"go\">                       &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: &#39;Long Wait&#39;}</span>\n</code></pre>\n</div>\n"}, "controlpi_plugins.wait.Wait": {"fullname": "controlpi_plugins.wait.Wait", "modulename": "controlpi_plugins.wait", "qualname": "Wait", "kind": "class", "doc": "<p>Wait for time defined in configuration.</p>\n\n<p>The \"seconds\" configuration key gets the number of seconds to wait after\nreceiving a \"wait\" command before sending the \"finished\" event:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Long Wait&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Wait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.02</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"s2\">&quot;Short Wait&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Wait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.01</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Long Wait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;wait&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Short Wait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;wait&quot;</span><span class=\"p\">}],</span> <span class=\"mf\">0.025</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Long Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Long Wait&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Short Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Short Wait&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Long Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Short Wait&#39;, &#39;command&#39;: &#39;wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Short Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Long Wait&#39;, &#39;event&#39;: &#39;finished&#39;}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"fullname": "controlpi_plugins.wait.Wait.CONF_SCHEMA", "modulename": "controlpi_plugins.wait", "qualname": "Wait.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Wait plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'seconds': number of seconds to wait.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;seconds&#x27;: {&#x27;type&#x27;: &#x27;number&#x27;}}, &#x27;required&#x27;: [&#x27;seconds&#x27;]}"}, "controlpi_plugins.wait.Wait.process_conf": {"fullname": "controlpi_plugins.wait.Wait.process_conf", "modulename": "controlpi_plugins.wait", "qualname": "Wait.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.wait.Wait.run": {"fullname": "controlpi_plugins.wait.Wait.run", "modulename": "controlpi_plugins.wait", "qualname": "Wait.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.wait.GenericWait": {"fullname": "controlpi_plugins.wait.GenericWait", "modulename": "controlpi_plugins.wait", "qualname": "GenericWait", "kind": "class", "doc": "<p>Wait for time defined in \"wait\" command.</p>\n\n<p>The \"wait\" command has message keys \"seconds\" defining the seconds to\nwait and \"id\" defining a string to be sent back in the \"finished\" event\nafter the wait:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Test GenericWait&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;GenericWait&quot;</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test GenericWait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;wait&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.02</span><span class=\"p\">,</span> <span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Long Wait&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Test GenericWait&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;wait&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>      <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.01</span><span class=\"p\">,</span> <span class=\"s2\">&quot;id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Short Wait&quot;</span><span class=\"p\">}],</span> <span class=\"mf\">0.025</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},</span>\n<span class=\"go\">                    &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},</span>\n<span class=\"go\">                       &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},</span>\n<span class=\"go\">                       &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,</span>\n<span class=\"go\">         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.01, &#39;id&#39;: &#39;Short Wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: &#39;Short Wait&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,</span>\n<span class=\"go\">         &#39;id&#39;: &#39;Long Wait&#39;}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"fullname": "controlpi_plugins.wait.GenericWait.CONF_SCHEMA", "modulename": "controlpi_plugins.wait", "qualname": "GenericWait.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for GenericWait plugin configuration.</p>\n\n<p>There are no required or optional configuration keys.</p>\n", "default_value": "True"}, "controlpi_plugins.wait.GenericWait.process_conf": {"fullname": "controlpi_plugins.wait.GenericWait.process_conf", "modulename": "controlpi_plugins.wait", "qualname": "GenericWait.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.wait.GenericWait.run": {"fullname": "controlpi_plugins.wait.GenericWait.run", "modulename": "controlpi_plugins.wait", "qualname": "GenericWait.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.wait.Timer": {"fullname": "controlpi_plugins.wait.Timer", "modulename": "controlpi_plugins.wait", "qualname": "Timer", "kind": "class", "doc": "<p>Timer that can be started and cancelled.</p>\n\n<p>The \"seconds\" configuration key gets the number of seconds to wait after\nreceiving a \"start\" command before sending the \"finished\" event.\nThe \"cancel\" command cancels all outstanding \"finished\" events and sends\na corresponding \"cancelled\" event:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.01</span><span class=\"p\">}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;start&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;start&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;cancel&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;start&quot;</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>     <span class=\"p\">{</span><span class=\"s2\">&quot;target&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Timer&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;command&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;start&quot;</span><span class=\"p\">}],</span> <span class=\"mf\">0.015</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Timer&#39;, &#39;plugin&#39;: &#39;Timer&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}},</span>\n<span class=\"go\">                   {&#39;event&#39;: {&#39;const&#39;: &#39;cancelled&#39;}}],</span>\n<span class=\"go\">         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;start&#39;}},</span>\n<span class=\"go\">                      {&#39;target&#39;: {&#39;const&#39;: &#39;Timer&#39;},</span>\n<span class=\"go\">                       &#39;command&#39;: {&#39;const&#39;: &#39;cancel&#39;}}]}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;cancel&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;cancelled&#39;, &#39;count&#39;: 2}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Timer&#39;, &#39;command&#39;: &#39;start&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Timer&#39;, &#39;event&#39;: &#39;finished&#39;}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"fullname": "controlpi_plugins.wait.Timer.CONF_SCHEMA", "modulename": "controlpi_plugins.wait", "qualname": "Timer.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Timer plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'seconds': number of seconds to wait.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;seconds&#x27;: {&#x27;type&#x27;: &#x27;number&#x27;}}, &#x27;required&#x27;: [&#x27;seconds&#x27;]}"}, "controlpi_plugins.wait.Timer.process_conf": {"fullname": "controlpi_plugins.wait.Timer.process_conf", "modulename": "controlpi_plugins.wait", "qualname": "Timer.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.wait.Timer.run": {"fullname": "controlpi_plugins.wait.Timer.run", "modulename": "controlpi_plugins.wait", "qualname": "Timer.run", "kind": "function", "doc": "<p>Run no code proactively.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}, "controlpi_plugins.wait.Periodic": {"fullname": "controlpi_plugins.wait.Periodic", "modulename": "controlpi_plugins.wait", "qualname": "Periodic", "kind": "class", "doc": "<p>Send message periodically.</p>\n\n<p>The \"seconds\" configuration key is the period of the repetition:\nreceiving a \"wait\" command before sending the \"finished\" event:</p>\n\n<div class=\"pdoc-code codehilite\">\n<pre><span></span><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">controlpi</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">asyncio</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">controlpi</span><span class=\"o\">.</span><span class=\"n\">test</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s2\">&quot;Loop&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;plugin&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Periodic&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;seconds&quot;</span><span class=\"p\">:</span> <span class=\"mf\">0.01</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>              <span class=\"s2\">&quot;message&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;key&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;value&quot;</span><span class=\"p\">}}},</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[],</span> <span class=\"mf\">0.025</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span><span class=\"c1\"># doctest: +NORMALIZE_WHITESPACE</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,</span>\n<span class=\"go\">         &#39;client&#39;: &#39;Loop&#39;, &#39;plugin&#39;: &#39;Periodic&#39;,</span>\n<span class=\"go\">         &#39;sends&#39;: [{&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}], &#39;receives&#39;: []}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>\n<span class=\"go\">test(): {&#39;sender&#39;: &#39;Loop&#39;, &#39;key&#39;: &#39;value&#39;}</span>\n</code></pre>\n</div>\n", "bases": "controlpi.baseplugin.BasePlugin"}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"fullname": "controlpi_plugins.wait.Periodic.CONF_SCHEMA", "modulename": "controlpi_plugins.wait", "qualname": "Periodic.CONF_SCHEMA", "kind": "variable", "doc": "<p>Schema for Wait plugin configuration.</p>\n\n<p>Required configuration key:</p>\n\n<ul>\n<li>'seconds': period of repetition in seconds.</li>\n<li>'message': message to send periodically.</li>\n</ul>\n", "default_value": "{&#x27;properties&#x27;: {&#x27;seconds&#x27;: {&#x27;type&#x27;: &#x27;number&#x27;}, &#x27;message&#x27;: {&#x27;type&#x27;: &#x27;object&#x27;}}, &#x27;required&#x27;: [&#x27;seconds&#x27;, &#x27;message&#x27;]}"}, "controlpi_plugins.wait.Periodic.process_conf": {"fullname": "controlpi_plugins.wait.Periodic.process_conf", "modulename": "controlpi_plugins.wait", "qualname": "Periodic.process_conf", "kind": "function", "doc": "<p>Register plugin as bus client.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "def"}, "controlpi_plugins.wait.Periodic.run": {"fullname": "controlpi_plugins.wait.Periodic.run", "modulename": "controlpi_plugins.wait", "qualname": "Periodic.run", "kind": "function", "doc": "<p>Run periodic loop.</p>\n", "signature": "<span class=\"signature pdoc-code condensed\">(<span class=\"param\"><span class=\"bp\">self</span></span><span class=\"return-annotation\">) -> <span class=\"kc\">None</span>:</span></span>", "funcdef": "async def"}}, "docInfo": {"controlpi": {"qualname": 0, "fullname": 1, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 82}, "controlpi.CONF_SCHEMA": {"qualname": 2, "fullname": 3, "annotation": 0, "default_value": 26, "signature": 0, "bases": 0, "doc": 3}, "controlpi.run": {"qualname": 1, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 41, "bases": 0, "doc": 536}, "controlpi.test": {"qualname": 1, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 88, "bases": 0, "doc": 750}, "controlpi.baseplugin": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 1755}, "controlpi.baseplugin.JSONSchema": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 22, "signature": 0, "bases": 0, "doc": 3}, "controlpi.baseplugin.PluginConf": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 4, "signature": 0, "bases": 0, "doc": 3}, "controlpi.baseplugin.ConfException": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 2, "doc": 9}, "controlpi.baseplugin.BasePlugin": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 2, "doc": 1076}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"qualname": 3, "fullname": 5, "annotation": 18, "default_value": 1, "signature": 0, "bases": 0, "doc": 3}, "controlpi.baseplugin.BasePlugin.bus": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "controlpi.baseplugin.BasePlugin.name": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "controlpi.baseplugin.BasePlugin.conf": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "controlpi.baseplugin.BasePlugin.process_conf": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 50}, "controlpi.baseplugin.BasePlugin.run": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 49}, "controlpi.messagebus": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 1501}, "controlpi.messagebus.MessageValue": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 18, "signature": 0, "bases": 0, "doc": 3}, "controlpi.messagebus.JSONSchema": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 22, "signature": 0, "bases": 0, "doc": 3}, "controlpi.messagebus.MessageCallback": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 12, "signature": 0, "bases": 0, "doc": 3}, "controlpi.messagebus.register_schema": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 90, "bases": 0, "doc": 12}, "controlpi.messagebus.validate": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 86, "bases": 0, "doc": 13}, "controlpi.messagebus.Message": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 20, "doc": 725}, "controlpi.messagebus.Message.__init__": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 103, "bases": 0, "doc": 178}, "controlpi.messagebus.Message.check_value": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 74, "bases": 0, "doc": 670}, "controlpi.messagebus.Message.update": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 28, "bases": 0, "doc": 556}, "controlpi.messagebus.Message.setdefault": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 152, "bases": 0, "doc": 340}, "controlpi.messagebus.MessageTemplate": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 24, "doc": 494}, "controlpi.messagebus.MessageTemplate.__init__": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 108, "bases": 0, "doc": 148}, "controlpi.messagebus.MessageTemplate.from_message": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 40, "bases": 0, "doc": 473}, "controlpi.messagebus.MessageTemplate.update": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 28, "bases": 0, "doc": 1029}, "controlpi.messagebus.MessageTemplate.setdefault": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 190, "bases": 0, "doc": 556}, "controlpi.messagebus.MessageTemplate.check": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 34, "bases": 0, "doc": 1682}, "controlpi.messagebus.TemplateRegistry": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3554}, "controlpi.messagebus.TemplateRegistry.__init__": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 4, "bases": 0, "doc": 37}, "controlpi.messagebus.TemplateRegistry.insert": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 109, "bases": 0, "doc": 416}, "controlpi.messagebus.TemplateRegistry.delete": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 24, "bases": 0, "doc": 476}, "controlpi.messagebus.TemplateRegistry.check": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 44, "bases": 0, "doc": 766}, "controlpi.messagebus.TemplateRegistry.get": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 40, "bases": 0, "doc": 466}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 78, "bases": 0, "doc": 12}, "controlpi.messagebus.TemplateRegistry.get_templates": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 40, "bases": 0, "doc": 762}, "controlpi.messagebus.BusException": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 2, "doc": 10}, "controlpi.messagebus.MessageBus": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 1839}, "controlpi.messagebus.MessageBus.__init__": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 4, "bases": 0, "doc": 79}, "controlpi.messagebus.MessageBus.register": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 141, "bases": 0, "doc": 488}, "controlpi.messagebus.MessageBus.unregister": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 24, "bases": 0, "doc": 282}, "controlpi.messagebus.MessageBus.run": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 177}, "controlpi.messagebus.MessageBus.send": {"qualname": 2, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 34, "bases": 0, "doc": 852}, "controlpi.messagebus.MessageBus.send_nowait": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 34, "bases": 0, "doc": 848}, "controlpi.pluginregistry": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 465}, "controlpi.pluginregistry.PluginRegistry": {"qualname": 1, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 376}, "controlpi.pluginregistry.PluginRegistry.__init__": {"qualname": 3, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 26, "bases": 0, "doc": 261}, "controlpi_plugins": {"qualname": 0, "fullname": 2, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 3}, "controlpi_plugins.state": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 1650}, "controlpi_plugins.state.State": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 618}, "controlpi_plugins.state.State.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 1, "signature": 0, "bases": 0, "doc": 19}, "controlpi_plugins.state.State.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.state.State.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.state.StateAlias": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 810}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 30, "signature": 0, "bases": 0, "doc": 28}, "controlpi_plugins.state.StateAlias.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.state.StateAlias.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.state.AndState": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 948}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 40, "signature": 0, "bases": 0, "doc": 29}, "controlpi_plugins.state.AndState.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.state.AndState.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.state.OrState": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 923}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 40, "signature": 0, "bases": 0, "doc": 29}, "controlpi_plugins.state.OrState.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.state.OrState.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.state.AndSet": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 1260}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 60, "signature": 0, "bases": 0, "doc": 43}, "controlpi_plugins.state.AndSet.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.state.AndSet.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.state.OrSet": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 1056}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 60, "signature": 0, "bases": 0, "doc": 43}, "controlpi_plugins.state.OrSet.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.state.OrSet.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.util": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 806}, "controlpi_plugins.util.Log": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 774}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 40, "signature": 0, "bases": 0, "doc": 30}, "controlpi_plugins.util.Log.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Log.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.util.Init": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 850}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 40, "signature": 0, "bases": 0, "doc": 29}, "controlpi_plugins.util.Init.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Init.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Execute": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 685}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 1, "signature": 0, "bases": 0, "doc": 19}, "controlpi_plugins.util.Execute.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Execute.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.util.Alias": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 1688}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 122, "signature": 0, "bases": 0, "doc": 64}, "controlpi_plugins.util.Alias.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Alias.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.util.Counter": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 1198}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 52, "signature": 0, "bases": 0, "doc": 29}, "controlpi_plugins.util.Counter.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Counter.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.util.Date": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 648}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 29, "signature": 0, "bases": 0, "doc": 34}, "controlpi_plugins.util.Date.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.util.Date.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.wait": {"qualname": 0, "fullname": 3, "annotation": 0, "default_value": 0, "signature": 0, "bases": 0, "doc": 714}, "controlpi_plugins.wait.Wait": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 590}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 28, "signature": 0, "bases": 0, "doc": 28}, "controlpi_plugins.wait.Wait.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.wait.Wait.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.wait.GenericWait": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 623}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 1, "signature": 0, "bases": 0, "doc": 19}, "controlpi_plugins.wait.GenericWait.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.wait.GenericWait.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.wait.Timer": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 736}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 28, "signature": 0, "bases": 0, "doc": 28}, "controlpi_plugins.wait.Timer.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.wait.Timer.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 7}, "controlpi_plugins.wait.Periodic": {"qualname": 1, "fullname": 4, "annotation": 0, "default_value": 0, "signature": 0, "bases": 3, "doc": 292}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 44, "signature": 0, "bases": 0, "doc": 38}, "controlpi_plugins.wait.Periodic.process_conf": {"qualname": 3, "fullname": 6, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 8}, "controlpi_plugins.wait.Periodic.run": {"qualname": 2, "fullname": 5, "annotation": 0, "default_value": 0, "signature": 14, "bases": 0, "doc": 6}}, "length": 119, "save": true}, "index": {"qualname": {"root": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 5, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 36, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin.ConfException": {"tf": 1}}, "df": 1}}}}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}}, "df": 4}}}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}}, "df": 3}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}}, "df": 1}}}}}}}}}, "s": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 19}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 2}}}}}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 2}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}}, "df": 4, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}}, "df": 4}}}}}}}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 19}}, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 2}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 8}}}}}}}}, "s": {"docs": {"controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 1}}}}}}}}, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}}, "df": 4}}}}}, "j": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 2}}}}}}}}}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.baseplugin.PluginConf": {"tf": 1}}, "df": 1}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 2}}}}}}}}}}}}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 17}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 4}}}}}}}}, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.bus": {"tf": 1}, "controlpi.baseplugin.BasePlugin.name": {"tf": 1}, "controlpi.baseplugin.BasePlugin.conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}}, "df": 7}}}}}}}}}, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.BasePlugin.bus": {"tf": 1}}, "df": 1, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.BusException": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.name": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 1}}}}}}, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 6, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageValue": {"tf": 1}}, "df": 1}}}}}, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus.MessageCallback": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 6}}}}}}}}, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 7}}}}}}}}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.validate": {"tf": 1}}, "df": 1}}}}}, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}}, "df": 9}}, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}}, "df": 1}}}}}}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}}, "df": 2}}}}}, "n": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.MessageBus.unregister": {"tf": 1}}, "df": 1}}}}}}}}}}, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}}, "df": 4}}}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 3}, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}}, "df": 4}}}}}}}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}}, "df": 4}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}}, "df": 4}}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}}, "df": 4}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}}, "df": 4}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}}, "df": 4}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}}, "df": 4}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}}, "df": 4}}}}}}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}}, "df": 4}}}}}}, "fullname": {"root": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 5, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {"controlpi": {"tf": 1}, "controlpi.CONF_SCHEMA": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.baseplugin.PluginConf": {"tf": 1}, "controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.bus": {"tf": 1}, "controlpi.baseplugin.BasePlugin.name": {"tf": 1}, "controlpi.baseplugin.BasePlugin.conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageCallback": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 119}}}}}}, "f": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 36, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin.ConfException": {"tf": 1}}, "df": 1}}}}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}}, "df": 4}}}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}}, "df": 3}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}}, "df": 1}}}}}}}}}, "s": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 19}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 2}}}}}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 2}}}, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.process_conf": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.run": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}}, "df": 25, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}}, "df": 4}}}}}}}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 19}}, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 2}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 8}}}}}}}}, "s": {"docs": {"controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 1}}}}}}}}, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}}, "df": 4}}}}}, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.baseplugin.PluginConf": {"tf": 1}, "controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.bus": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.name": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.conf": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}}, "df": 11}}}}}}}}}, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.BasePlugin.bus": {"tf": 1}}, "df": 1, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.BusException": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "j": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 2}}}}}}}}}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.baseplugin.PluginConf": {"tf": 1}}, "df": 1}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.4142135623730951}}, "df": 3}}}}}}}}, "s": {"docs": {"controlpi_plugins": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 68}}}}}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 17}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 4}}}}}}}}, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.name": {"tf": 1}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 1}}}}}}, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 6, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageCallback": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.run": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 33}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageValue": {"tf": 1}}, "df": 1}}}}}, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus.MessageCallback": {"tf": 1}}, "df": 1}}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 6}}}}}}}}}}}}}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.validate": {"tf": 1}}, "df": 1}}}}}, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}}, "df": 9}}, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}}, "df": 1}}}}}}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}}, "df": 2}}}}}, "n": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.MessageBus.unregister": {"tf": 1}}, "df": 1}}}}}}}}}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {"controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}}, "df": 25}}}}, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}}, "df": 4}}}}, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 3}, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}}, "df": 4}}}}}}}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}}, "df": 4}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}}, "df": 4}}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}}, "df": 4}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}}, "df": 4}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}}, "df": 4}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}}, "df": 4}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}}, "df": 4}}}}}}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait.run": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 17}}}}}}, "annotation": {"root": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 2.8284271247461903}}, "df": 1, "b": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}, "f": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}}}}}}, "default_value": {"root": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 3}, "controlpi.baseplugin.JSONSchema": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageValue": {"tf": 2.449489742783178}, "controlpi.messagebus.JSONSchema": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageCallback": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 3.1622776601683795}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 3.605551275463989}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 3.605551275463989}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 4.123105625617661}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 4.123105625617661}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 3.605551275463989}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 3.605551275463989}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 6.164414002968976}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 3.872983346207417}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 2.8284271247461903}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 3.1622776601683795}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 3.1622776601683795}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 3.7416573867739413}}, "df": 18, "x": {"2": {"7": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageCallback": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 3.4641016151377544}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 4.242640687119285}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 4.242640687119285}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 5.0990195135927845}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 5.0990195135927845}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 4.242640687119285}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 4.242640687119285}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 7.483314773547883}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 4.69041575982343}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 4.47213595499958}}, "df": 15}, "docs": {}, "df": 0}, "docs": {}, "df": 0}, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 2.8284271247461903}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 14}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 2}, "controlpi.baseplugin.PluginConf": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageValue": {"tf": 1.7320508075688772}, "controlpi.messagebus.JSONSchema": {"tf": 2}, "controlpi.messagebus.MessageCallback": {"tf": 1.7320508075688772}}, "df": 5}}}}}, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 3}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}}}}, "o": {"docs": {"controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}, "o": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "j": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 2}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 6}}}}}, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 2}}}}}}, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}}}}}}}}}}}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 13}}}}}}}}}}, "b": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1.4142135623730951}}, "df": 3}}}}, "d": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1.4142135623730951}, "controlpi.baseplugin.PluginConf": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1.4142135623730951}}, "df": 4}}}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}}}, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 3, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageCallback": {"tf": 1}}, "df": 1}}}}}}}, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 3, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 8}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 2, "s": {"docs": {"controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 4}}}}}, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 3}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 3}, "p": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 2}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 7}}}}}, "f": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 3}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}}}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {"controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.7320508075688772}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1.4142135623730951}, "controlpi.baseplugin.PluginConf": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1.4142135623730951}, "controlpi.messagebus.JSONSchema": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageCallback": {"tf": 1.4142135623730951}}, "df": 5, "o": {"docs": {}, "df": 0, "f": {"docs": {"controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}}}, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "y": {"docs": {"controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 7}}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin.JSONSchema": {"tf": 1}, "controlpi.messagebus.MessageValue": {"tf": 1}, "controlpi.messagebus.JSONSchema": {"tf": 1}}, "df": 3}}}}}}}}}}}, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.messagebus.MessageCallback": {"tf": 1}}, "df": 1}}}}}}}}}}}}}}}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.MessageCallback": {"tf": 1}}, "df": 1}}}}}}}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}}}}, "m": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageCallback": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 2, "s": {"docs": {"controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 12}}}}}}}}, "y": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2}, "h": {"docs": {}, "df": 0, ":": {"docs": {}, "df": 0, "%": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, ":": {"docs": {}, "df": 0, "%": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}}}}}, "signature": {"root": {"0": {"docs": {"controlpi.test": {"tf": 1.4142135623730951}}, "df": 1}, "docs": {"controlpi.run": {"tf": 5.830951894845301}, "controlpi.test": {"tf": 8.48528137423857}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 3.4641016151377544}, "controlpi.baseplugin.BasePlugin.run": {"tf": 3.4641016151377544}, "controlpi.messagebus.register_schema": {"tf": 8.660254037844387}, "controlpi.messagebus.validate": {"tf": 8.426149773176359}, "controlpi.messagebus.Message.__init__": {"tf": 9.273618495495704}, "controlpi.messagebus.Message.check_value": {"tf": 7.874007874011811}, "controlpi.messagebus.Message.update": {"tf": 4.898979485566356}, "controlpi.messagebus.Message.setdefault": {"tf": 11.269427669584644}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 9.486832980505138}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 5.744562646538029}, "controlpi.messagebus.MessageTemplate.update": {"tf": 4.898979485566356}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 12.569805089976535}, "controlpi.messagebus.MessageTemplate.check": {"tf": 5.291502622129181}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 9.486832980505138}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 4.47213595499958}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 6}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 5.744562646538029}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 8}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 5.744562646538029}, "controlpi.messagebus.MessageBus.__init__": {"tf": 2}, "controlpi.messagebus.MessageBus.register": {"tf": 10.723805294763608}, "controlpi.messagebus.MessageBus.unregister": {"tf": 4.47213595499958}, "controlpi.messagebus.MessageBus.run": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageBus.send": {"tf": 5.291502622129181}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 5.291502622129181}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 4.47213595499958}, "controlpi_plugins.state.State.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.state.State.run": {"tf": 3.4641016151377544}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.state.StateAlias.run": {"tf": 3.4641016151377544}, "controlpi_plugins.state.AndState.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.state.AndState.run": {"tf": 3.4641016151377544}, "controlpi_plugins.state.OrState.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.state.OrState.run": {"tf": 3.4641016151377544}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.state.AndSet.run": {"tf": 3.4641016151377544}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.state.OrSet.run": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Log.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Log.run": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Init.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Init.run": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Execute.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Execute.run": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Alias.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Alias.run": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Counter.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Counter.run": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Date.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Date.run": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Wait.run": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.GenericWait.run": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Timer.run": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 3.4641016151377544}, "controlpi_plugins.wait.Periodic.run": {"tf": 3.4641016151377544}}, "df": 61, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}}, "df": 2}, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 10}}}}}}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 3}}}}}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}}, "df": 6}}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 3}}}}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 1.7320508075688772}, "controlpi.messagebus.register_schema": {"tf": 1.4142135623730951}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}}, "df": 9}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 1.7320508075688772}, "controlpi.messagebus.register_schema": {"tf": 1.7320508075688772}, "controlpi.messagebus.validate": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.__init__": {"tf": 2}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2.6457513110645907}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 17, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.validate": {"tf": 1}}, "df": 1}}}}}, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 50}}, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}}, "df": 1}}, "s": {"docs": {"controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 1}}}}, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}}, "df": 2}}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.messagebus.register_schema": {"tf": 1.4142135623730951}, "controlpi.messagebus.validate": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}}, "df": 12}}, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}}, "df": 2}}}}, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 51, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 3}}}}}}}, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}}}}}}}, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 9, "s": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 10}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}}, "df": 4}}}}}}}}}}}}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 11}}}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}, "f": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 8}}}}}, "b": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.register_schema": {"tf": 1.7320508075688772}, "controlpi.messagebus.validate": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}}, "df": 10}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 7}, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}}, "df": 2}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}}, "df": 1}}}}}}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 4}}}}}, "k": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}}, "df": 2}}}}}, "e": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 2}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}}, "df": 1}}}}}}}, "u": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 1}}}}, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 1}}}}}}}}}}, "bases": {"root": {"docs": {"controlpi.messagebus.Message": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate": {"tf": 2.6457513110645907}}, "df": 2, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}}, "df": 2}}}}}}}, "o": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}}, "df": 2}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}}, "df": 16}}}}}}}}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}}, "df": 2}}}}}}}}}, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "c": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 2}}, "n": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}}, "df": 2}}}, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.Message": {"tf": 2}, "controlpi.messagebus.MessageTemplate": {"tf": 2.23606797749979}}, "df": 2}}}}}}, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.7320508075688772}}, "df": 2}}}}}}}}, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}}, "f": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "[": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}}}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1}}}}}}}}}, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {"controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 16}}}}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1}}}}}}}}}, "doc": {"root": {"0": {"1": {"5": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 1}, "docs": {"controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 5}, "2": {"5": {"docs": {"controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 4}, "docs": {"controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}}, "df": 3}, "docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 2}, "controlpi_plugins.wait.Wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait": {"tf": 2.23606797749979}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}}, "df": 13, "x": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}}, "df": 1}}, "1": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.messagebus": {"tf": 3.872983346207417}, "controlpi.messagebus.Message": {"tf": 2.8284271247461903}, "controlpi.messagebus.Message.__init__": {"tf": 2}, "controlpi.messagebus.Message.check_value": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.update": {"tf": 2.449489742783178}, "controlpi.messagebus.Message.setdefault": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate": {"tf": 2}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.6457513110645907}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send": {"tf": 3}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 3}, "controlpi_plugins.state.AndState": {"tf": 3}, "controlpi_plugins.state.OrState": {"tf": 3}, "controlpi_plugins.state.AndSet": {"tf": 3}, "controlpi_plugins.state.OrSet": {"tf": 3}}, "df": 26, "j": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 1}}, "df": 2}}, "2": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.Message": {"tf": 2.8284271247461903}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 2}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.6457513110645907}, "controlpi.messagebus.TemplateRegistry": {"tf": 6.244997998398398}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 3.1622776601683795}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 2.6457513110645907}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2}, "controlpi.messagebus.MessageBus": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2.8284271247461903}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 2}, "controlpi_plugins.state.AndState": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrState": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndSet": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrSet": {"tf": 2.449489742783178}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 28}, "3": {"9": {"docs": {"controlpi.run": {"tf": 4.47213595499958}, "controlpi.test": {"tf": 10.392304845413264}, "controlpi.baseplugin": {"tf": 10.099504938362077}, "controlpi.baseplugin.BasePlugin": {"tf": 7.874007874011811}, "controlpi.messagebus": {"tf": 11.74734012447073}, "controlpi.messagebus.Message": {"tf": 9.273618495495704}, "controlpi.messagebus.Message.__init__": {"tf": 4.47213595499958}, "controlpi.messagebus.Message.check_value": {"tf": 4.47213595499958}, "controlpi.messagebus.Message.update": {"tf": 7.483314773547883}, "controlpi.messagebus.Message.setdefault": {"tf": 5.0990195135927845}, "controlpi.messagebus.MessageTemplate": {"tf": 7.0710678118654755}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 8.246211251235321}, "controlpi.messagebus.MessageTemplate.update": {"tf": 11.832159566199232}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 8.366600265340756}, "controlpi.messagebus.MessageTemplate.check": {"tf": 12.489995996796797}, "controlpi.messagebus.TemplateRegistry": {"tf": 24.819347291981714}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 7.615773105863909}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 7.874007874011811}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 11.489125293076057}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 8.94427190999916}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 10.862780491200215}, "controlpi.messagebus.MessageBus": {"tf": 15.620499351813308}, "controlpi.messagebus.MessageBus.register": {"tf": 5.656854249492381}, "controlpi.messagebus.MessageBus.unregister": {"tf": 4.242640687119285}, "controlpi.messagebus.MessageBus.send": {"tf": 9.486832980505138}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 9.486832980505138}, "controlpi.pluginregistry": {"tf": 3.7416573867739413}, "controlpi.pluginregistry.PluginRegistry": {"tf": 3.4641016151377544}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 2.449489742783178}, "controlpi_plugins.state": {"tf": 12.806248474865697}, "controlpi_plugins.state.State": {"tf": 9.38083151964686}, "controlpi_plugins.state.StateAlias": {"tf": 11.40175425099138}, "controlpi_plugins.state.AndState": {"tf": 11.832159566199232}, "controlpi_plugins.state.OrState": {"tf": 11.40175425099138}, "controlpi_plugins.state.AndSet": {"tf": 14.628738838327793}, "controlpi_plugins.state.OrSet": {"tf": 12.569805089976535}, "controlpi_plugins.util": {"tf": 11.74734012447073}, "controlpi_plugins.util.Log": {"tf": 8.94427190999916}, "controlpi_plugins.util.Init": {"tf": 10.488088481701515}, "controlpi_plugins.util.Execute": {"tf": 10.677078252031311}, "controlpi_plugins.util.Alias": {"tf": 14.142135623730951}, "controlpi_plugins.util.Counter": {"tf": 14.7648230602334}, "controlpi_plugins.util.Date": {"tf": 10.583005244258363}, "controlpi_plugins.wait": {"tf": 12}, "controlpi_plugins.wait.Wait": {"tf": 10.770329614269007}, "controlpi_plugins.wait.GenericWait": {"tf": 10.770329614269007}, "controlpi_plugins.wait.Timer": {"tf": 11.916375287812984}, "controlpi_plugins.wait.Periodic": {"tf": 6.48074069840786}}, "df": 49}, "docs": {"controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 3.1622776601683795}, "controlpi_plugins.state.OrSet": {"tf": 2.449489742783178}, "controlpi_plugins.util.Counter": {"tf": 1}}, "df": 12}, "4": {"2": {"docs": {"controlpi.run": {"tf": 2.449489742783178}, "controlpi.test": {"tf": 3.4641016151377544}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 3.1622776601683795}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 2.23606797749979}, "controlpi_plugins.util.Log": {"tf": 3.605551275463989}, "controlpi_plugins.util.Init": {"tf": 3.605551275463989}, "controlpi_plugins.util.Execute": {"tf": 3}, "controlpi_plugins.util.Alias": {"tf": 3.7416573867739413}, "controlpi_plugins.util.Counter": {"tf": 4.242640687119285}}, "df": 19}, "9": {"docs": {"controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}}, "df": 1}, "docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 2}}, "df": 5}, "5": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}}, "df": 5}, "6": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.7320508075688772}}, "df": 2}, "7": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1.7320508075688772}}, "df": 1}, "docs": {"controlpi": {"tf": 3.4641016151377544}, "controlpi.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi.run": {"tf": 18.601075237738275}, "controlpi.test": {"tf": 19.183326093250876}, "controlpi.baseplugin": {"tf": 33.04542328371661}, "controlpi.baseplugin.JSONSchema": {"tf": 1.7320508075688772}, "controlpi.baseplugin.PluginConf": {"tf": 1.7320508075688772}, "controlpi.baseplugin.ConfException": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 27.349588662354687}, "controlpi.baseplugin.BasePlugin.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.bus": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.name": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.conf": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 2.449489742783178}, "controlpi.baseplugin.BasePlugin.run": {"tf": 2.449489742783178}, "controlpi.messagebus": {"tf": 27.910571473905726}, "controlpi.messagebus.MessageValue": {"tf": 1.7320508075688772}, "controlpi.messagebus.JSONSchema": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageCallback": {"tf": 1.7320508075688772}, "controlpi.messagebus.register_schema": {"tf": 1.7320508075688772}, "controlpi.messagebus.validate": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 19.8997487421324}, "controlpi.messagebus.Message.__init__": {"tf": 10.295630140987}, "controlpi.messagebus.Message.check_value": {"tf": 21.166010488516726}, "controlpi.messagebus.Message.update": {"tf": 18.24828759089466}, "controlpi.messagebus.Message.setdefault": {"tf": 14.560219778561036}, "controlpi.messagebus.MessageTemplate": {"tf": 17.944358444926362}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 9.899494936611665}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 16.55294535724685}, "controlpi.messagebus.MessageTemplate.update": {"tf": 25.337718918639855}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 18.627936010197157}, "controlpi.messagebus.MessageTemplate.check": {"tf": 34.02939905434711}, "controlpi.messagebus.TemplateRegistry": {"tf": 46.87216658103186}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 5.291502622129181}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 16.97056274847714}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 18.110770276274835}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 22.22611077089287}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 17.26267650163207}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 22.090722034374522}, "controlpi.messagebus.BusException": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 31.368774282716245}, "controlpi.messagebus.MessageBus.__init__": {"tf": 7.681145747868608}, "controlpi.messagebus.MessageBus.register": {"tf": 19.209372712298546}, "controlpi.messagebus.MessageBus.unregister": {"tf": 14.628738838327793}, "controlpi.messagebus.MessageBus.run": {"tf": 11.789826122551595}, "controlpi.messagebus.MessageBus.send": {"tf": 24.576411454889016}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 24.454038521274967}, "controlpi.pluginregistry": {"tf": 16.24807680927192}, "controlpi.pluginregistry.PluginRegistry": {"tf": 15.033296378372908}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 13}, "controlpi_plugins": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 29}, "controlpi_plugins.state.State": {"tf": 18.027756377319946}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 2.449489742783178}, "controlpi_plugins.state.State.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.state.State.run": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias": {"tf": 20.174241001832016}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias.run": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndState": {"tf": 22.090722034374522}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndState.run": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrState": {"tf": 21.93171219946131}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrState.run": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndSet": {"tf": 25.13961017995307}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 4.358898943540674}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndSet.run": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrSet": {"tf": 23.473389188611005}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 4.358898943540674}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrSet.run": {"tf": 1.7320508075688772}, "controlpi_plugins.util": {"tf": 21}, "controlpi_plugins.util.Log": {"tf": 20.493901531919196}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.util.Log.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log.run": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init": {"tf": 21.18962010041709}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.util.Init.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init.run": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute": {"tf": 18.520259177452136}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 2.449489742783178}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute.run": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 30.331501776206203}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 5.477225575051661}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias.run": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Counter": {"tf": 25.337718918639855}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Counter.run": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Date": {"tf": 18.65475810617763}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.util.Date.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Date.run": {"tf": 1.7320508075688772}, "controlpi_plugins.wait": {"tf": 19.078784028338912}, "controlpi_plugins.wait.Wait": {"tf": 17.435595774162696}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Wait.run": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait": {"tf": 17.86057109949175}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Timer": {"tf": 19.519221295943137}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 3.7416573867739413}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Timer.run": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Periodic": {"tf": 12.84523257866513}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 4.358898943540674}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Periodic.run": {"tf": 1.7320508075688772}}, "df": 119, "p": {"1": {"docs": {"controlpi.pluginregistry": {"tf": 1.4142135623730951}}, "df": 1}, "docs": {"controlpi.baseplugin": {"tf": 2}, "controlpi.baseplugin.BasePlugin": {"tf": 2.449489742783178}}, "df": 2, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}}, "df": 9, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 2}}}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}}, "df": 5, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}}, "df": 2}}}}}}}, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 11}}}, "y": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}, "g": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}}}}}}}}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}}, "df": 14}}}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 2}, "controlpi.baseplugin.BasePlugin": {"tf": 2.6457513110645907}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 2.23606797749979}, "controlpi.messagebus.Message.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 3}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 21, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}}}, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 4}}, "r": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1}}}}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}}, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"1": {"docs": {"controlpi.pluginregistry": {"tf": 2.6457513110645907}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2.6457513110645907}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}}, "df": 3}, "2": {"docs": {"controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}}, "df": 3}, "docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 2.23606797749979}, "controlpi.baseplugin": {"tf": 3.7416573867739413}, "controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus": {"tf": 3.872983346207417}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 3}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 2}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 2}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 2}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 2}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util": {"tf": 2.449489742783178}, "controlpi_plugins.util.Log": {"tf": 2.23606797749979}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 2.6457513110645907}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 2.23606797749979}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait": {"tf": 2}, "controlpi_plugins.wait.Wait": {"tf": 2}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 64, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi": {"tf": 1}, "controlpi.pluginregistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}}, "df": 4}}}}}}}}, "s": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1.7320508075688772}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}}, "df": 13}}}}}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.4142135623730951}}, "df": 4, "s": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}}, "s": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}}, "df": 10}}, "i": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 6}}}, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}}, "df": 1, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}}, "df": 3}}}}}, "t": {"docs": {}, "df": 0, "h": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}, "y": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}}, "df": 2}, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}, "o": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 2, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}}}}}}}}, "t": {"docs": {"controlpi.messagebus.MessageTemplate": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 2}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2}, "controlpi.messagebus.MessageTemplate.update": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageTemplate.check": {"tf": 4.47213595499958}}, "df": 6, "h": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 2.8284271247461903}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 2}, "controlpi.baseplugin": {"tf": 5.477225575051661}, "controlpi.baseplugin.BasePlugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 2.23606797749979}, "controlpi.baseplugin.BasePlugin.run": {"tf": 2.23606797749979}, "controlpi.messagebus": {"tf": 5.196152422706632}, "controlpi.messagebus.register_schema": {"tf": 1.4142135623730951}, "controlpi.messagebus.validate": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 2.8284271247461903}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 3.1622776601683795}, "controlpi.messagebus.MessageBus": {"tf": 4.242640687119285}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 2.8284271247461903}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2.449489742783178}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.state.State": {"tf": 2.23606797749979}, "controlpi_plugins.state.StateAlias": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndSet": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrSet": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Init": {"tf": 2.8284271247461903}, "controlpi_plugins.util.Execute": {"tf": 2.6457513110645907}, "controlpi_plugins.util.Alias": {"tf": 4.47213595499958}, "controlpi_plugins.util.Counter": {"tf": 2.449489742783178}, "controlpi_plugins.util.Date": {"tf": 2}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait": {"tf": 2}, "controlpi_plugins.wait.Timer": {"tf": 2}, "controlpi_plugins.wait.Periodic": {"tf": 2}}, "df": 44, "m": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}}, "df": 2}, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1.7320508075688772}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 2}}, "df": 5}}, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 4, "f": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}}}}}, "y": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.state": {"tf": 2.23606797749979}}, "df": 3}, "i": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}}, "df": 4}}, "n": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}}, "df": 3}}, "i": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1}}, "df": 13}, "r": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.util.Log": {"tf": 2}}, "df": 1}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "h": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 10}}}, "o": {"docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 2.23606797749979}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 4}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 2.449489742783178}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 4.242640687119285}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 2}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 47}, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 2}, "controlpi.test": {"tf": 4.123105625617661}, "controlpi.baseplugin": {"tf": 4}, "controlpi.baseplugin.BasePlugin": {"tf": 3.4641016151377544}, "controlpi.messagebus": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 2}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2}, "controlpi_plugins.state": {"tf": 7.874007874011811}, "controlpi_plugins.state.State": {"tf": 5.196152422706632}, "controlpi_plugins.state.StateAlias": {"tf": 6.244997998398398}, "controlpi_plugins.state.AndState": {"tf": 6.557438524302}, "controlpi_plugins.state.OrState": {"tf": 6.4031242374328485}, "controlpi_plugins.state.AndSet": {"tf": 7.937253933193772}, "controlpi_plugins.state.OrSet": {"tf": 7}, "controlpi_plugins.util": {"tf": 5.0990195135927845}, "controlpi_plugins.util.Log": {"tf": 5}, "controlpi_plugins.util.Init": {"tf": 5.291502622129181}, "controlpi_plugins.util.Execute": {"tf": 4.795831523312719}, "controlpi_plugins.util.Alias": {"tf": 6.244997998398398}, "controlpi_plugins.util.Counter": {"tf": 7.3484692283495345}, "controlpi_plugins.util.Date": {"tf": 4.69041575982343}, "controlpi_plugins.wait": {"tf": 4.58257569495584}, "controlpi_plugins.wait.Wait": {"tf": 3}, "controlpi_plugins.wait.GenericWait": {"tf": 4.123105625617661}, "controlpi_plugins.wait.Timer": {"tf": 3.872983346207417}, "controlpi_plugins.wait.Periodic": {"tf": 2}}, "df": 30, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 2.23606797749979}}, "df": 2}}}}}}}}, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}}}}, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate": {"tf": 2}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}}, "df": 14, "s": {"docs": {"controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}}, "df": 9}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}}, "df": 7}}}}}}}}}}}}}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.run": {"tf": 2}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.run": {"tf": 2}, "controlpi.messagebus.MessageBus.send": {"tf": 2}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2}}, "df": 7, "s": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}}, "df": 1}}}, "r": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1.7320508075688772}, "controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2.8284271247461903}, "controlpi_plugins.state": {"tf": 3.7416573867739413}, "controlpi_plugins.state.State": {"tf": 2.8284271247461903}, "controlpi_plugins.state.StateAlias": {"tf": 3.1622776601683795}, "controlpi_plugins.state.AndState": {"tf": 3.1622776601683795}, "controlpi_plugins.state.OrState": {"tf": 3.1622776601683795}, "controlpi_plugins.state.AndSet": {"tf": 4}, "controlpi_plugins.state.OrSet": {"tf": 3.4641016151377544}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Execute": {"tf": 2.449489742783178}, "controlpi_plugins.util.Counter": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Date": {"tf": 2.449489742783178}, "controlpi_plugins.wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 2.23606797749979}, "controlpi_plugins.wait.Timer": {"tf": 3.4641016151377544}}, "df": 24}}}}}, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 7}, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 3}, "controlpi.messagebus.MessageTemplate": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 3.7416573867739413}, "controlpi.messagebus.TemplateRegistry": {"tf": 3.7416573867739413}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2}, "controlpi_plugins.state": {"tf": 3.1622776601683795}, "controlpi_plugins.state.State": {"tf": 2.6457513110645907}, "controlpi_plugins.state.StateAlias": {"tf": 3}, "controlpi_plugins.state.AndState": {"tf": 2.8284271247461903}, "controlpi_plugins.state.OrState": {"tf": 2.8284271247461903}, "controlpi_plugins.state.AndSet": {"tf": 3.1622776601683795}, "controlpi_plugins.state.OrSet": {"tf": 2.8284271247461903}}, "df": 17}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 5}}}}}}, "n": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Alias": {"tf": 2.6457513110645907}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 2, "s": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 1}}, "df": 2}, "d": {"docs": {"controlpi_plugins.util": {"tf": 2}, "controlpi_plugins.util.Alias": {"tf": 3}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.7320508075688772}}, "df": 3}}}}}}}}}, "y": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.6457513110645907}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait": {"tf": 1.7320508075688772}}, "df": 24, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 3}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 4}}}}}}}}, "w": {"docs": {}, "df": 0, "o": {"docs": {"controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 3}, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Init": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}}, "df": 4, "r": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 4.47213595499958}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}, "i": {"1": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}, "docs": {"controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 3, "n": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 2}, "controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.update": {"tf": 2.23606797749979}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 3.1622776601683795}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 2.449489742783178}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2.8284271247461903}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 2}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 35, "f": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}}, "df": 4}}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}}, "df": 1}}}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}}, "df": 3}}}}}}}}}, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}, "s": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 2.23606797749979}, "controlpi.test": {"tf": 3.872983346207417}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi_plugins.util": {"tf": 3}, "controlpi_plugins.util.Init": {"tf": 4.123105625617661}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}}, "df": 7, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 4}}}}}, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 7, "d": {"docs": {"controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 3}}}}}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}}}, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 2}, "controlpi.baseplugin.BasePlugin": {"tf": 2.6457513110645907}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}}, "df": 7, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}}, "df": 2}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 1}}}}}, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2.6457513110645907}}, "df": 6}}}}, "p": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}}, "df": 5, "/": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}}}}, "t": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 7, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}}, "df": 9, "s": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 3}}}}, "r": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 3}}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}, "s": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 1}}, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}}, "df": 1}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}}, "df": 1}}}}}}, "t": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 8, "s": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 3, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}}, "df": 2}}}}, "s": {"docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin": {"tf": 2}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 2.449489742783178}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 2.23606797749979}, "controlpi.messagebus.Message.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 2}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Alias": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 29}, "d": {"docs": {"controlpi.run": {"tf": 2}, "controlpi.test": {"tf": 2.8284271247461903}, "controlpi_plugins.util": {"tf": 3}, "controlpi_plugins.util.Log": {"tf": 3.1622776601683795}, "controlpi_plugins.util.Init": {"tf": 2.8284271247461903}, "controlpi_plugins.util.Execute": {"tf": 2.449489742783178}, "controlpi_plugins.util.Alias": {"tf": 4.58257569495584}, "controlpi_plugins.util.Counter": {"tf": 4.47213595499958}, "controlpi_plugins.wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 3}}, "df": 10}, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 22, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {"controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 3}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "f": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 2.449489742783178}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 14}}, "f": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 3}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 13, "o": {"docs": {}, "df": 0, "r": {"docs": {"controlpi": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 3}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry": {"tf": 3.872983346207417}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 4.358898943540674}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 2}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 49, "e": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}}, "df": 3}}}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}}, "df": 1}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Date": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 2}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 2}}}}}}}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "m": {"docs": {"controlpi": {"tf": 1.7320508075688772}, "controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 3.605551275463989}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 15}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi": {"tf": 1.7320508075688772}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}}, "df": 7, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}}, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}}, "df": 3}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.run": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 2.449489742783178}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}}, "df": 4, "[": {"0": {"docs": {"controlpi_plugins.util.Log": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0}}}}}, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Wait": {"tf": 2.23606797749979}, "controlpi_plugins.wait.GenericWait": {"tf": 2}, "controlpi_plugins.wait.Timer": {"tf": 2.23606797749979}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 5}}}}}}, "r": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}}, "df": 4}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 4, "s": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2}}, "df": 3}}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}}, "l": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry": {"tf": 4}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2}, "controlpi_plugins.state": {"tf": 2.23606797749979}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 2}, "controlpi_plugins.state.OrState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndSet": {"tf": 2.6457513110645907}, "controlpi_plugins.state.OrSet": {"tf": 2.23606797749979}}, "df": 11}}}}}, "c": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 6.6332495807108}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2.6457513110645907}}, "df": 3, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 2}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 2.449489742783178}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date": {"tf": 1.7320508075688772}, "controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}}, "df": 24}}}}}, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 2}, "controlpi.test": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi_plugins.util": {"tf": 2.23606797749979}, "controlpi_plugins.util.Init": {"tf": 2.8284271247461903}, "controlpi_plugins.util.Execute": {"tf": 2.449489742783178}, "controlpi_plugins.util.Alias": {"tf": 5}}, "df": 7}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.test": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}}, "df": 4, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi_plugins.state": {"tf": 2.23606797749979}}, "df": 2}}}, "s": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1}}}}}, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"controlpi": {"tf": 1}}, "df": 1}}}}, "t": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 2.449489742783178}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 3.605551275463989}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageBus": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 3.3166247903554}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 2.449489742783178}, "controlpi_plugins.util.Execute": {"tf": 2}, "controlpi_plugins.util.Alias": {"tf": 2.8284271247461903}, "controlpi_plugins.util.Counter": {"tf": 2.449489742783178}, "controlpi_plugins.util.Date": {"tf": 2}, "controlpi_plugins.wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Timer": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 33, "r": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": null}, "controlpi.messagebus.Message": {"tf": null}}, "df": 2}}, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.Message": {"tf": 1}}, "df": 1}}}, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.Message": {"tf": 1}}, "df": 1}}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}}, "df": 2}}}}}, "f": {"docs": {"controlpi.run": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 3}, "controlpi.baseplugin.BasePlugin": {"tf": 3.4641016151377544}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}}, "df": 4, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 2}, "controlpi.test": {"tf": 2}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi.baseplugin.BasePlugin": {"tf": 2}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 2.449489742783178}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 36, "s": {"docs": {"controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.messagebus": {"tf": 1}}, "df": 3}}}}}, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}}, "df": 2}}}}, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 4}}}}}, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}}, "df": 1}}}}}}}}}}, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}}, "df": 4}}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 3}}}}}, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 1, "s": {"docs": {"controlpi_plugins.state": {"tf": 2}}, "df": 1}}}}}}}}, "j": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1}}, "df": 3}}}}}}}}}, "m": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1, "s": {"docs": {"controlpi": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.4142135623730951}}, "df": 2}, "d": {"docs": {"controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}}, "df": 6}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi_plugins.state": {"tf": 3.7416573867739413}, "controlpi_plugins.state.State": {"tf": 3.1622776601683795}, "controlpi_plugins.state.StateAlias": {"tf": 3.1622776601683795}, "controlpi_plugins.state.AndState": {"tf": 3.1622776601683795}, "controlpi_plugins.state.OrState": {"tf": 3.1622776601683795}, "controlpi_plugins.state.AndSet": {"tf": 4}, "controlpi_plugins.state.OrSet": {"tf": 3.4641016151377544}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 2.23606797749979}, "controlpi_plugins.util.Execute": {"tf": 3.1622776601683795}, "controlpi_plugins.util.Counter": {"tf": 3.605551275463989}, "controlpi_plugins.util.Date": {"tf": 2.449489742783178}, "controlpi_plugins.wait": {"tf": 2.8284271247461903}, "controlpi_plugins.wait.Wait": {"tf": 2.6457513110645907}, "controlpi_plugins.wait.GenericWait": {"tf": 2.6457513110645907}, "controlpi_plugins.wait.Timer": {"tf": 3.7416573867739413}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 20, "s": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 7}}}}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}, "x": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 1}}, "df": 3}}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}}, "df": 19}}, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.run": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}}, "df": 3, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 2}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 2}}}}}}}}}}}, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 1}}, "df": 2}}, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Counter": {"tf": 4.242640687119285}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 3, "s": {"docs": {"controlpi_plugins.util.Counter": {"tf": 1}}, "df": 1}, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.util.Counter": {"tf": 4.69041575982343}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}}, "df": 2}, "d": {"docs": {"controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 8, "d": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 3}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 2}}, "df": 1}}}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 15, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 2}}, "df": 8, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 2}}, "df": 1, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 7}}}}}}}}, "s": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 1}}}}, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 4}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 5, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 4}}, "s": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}}, "df": 1}, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageBus.register": {"tf": 2}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.7320508075688772}}, "df": 6, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 3}}}}}}}, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}}, "df": 2}}}, "r": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}}, "df": 1}}, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.register_schema": {"tf": 1}}, "df": 1}}}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 4.242640687119285}, "controlpi.messagebus.TemplateRegistry": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus": {"tf": 6.324555320336759}, "controlpi.messagebus.MessageBus.register": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus.unregister": {"tf": 2}, "controlpi.messagebus.MessageBus.send": {"tf": 4.123105625617661}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 4.123105625617661}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 45, "s": {"docs": {"controlpi.baseplugin": {"tf": 2.449489742783178}, "controlpi.messagebus": {"tf": 3}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi_plugins.state": {"tf": 2.23606797749979}}, "df": 8}}}}}, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.pluginregistry": {"tf": 3.3166247903554}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2.449489742783178}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 2.449489742783178}}, "df": 5, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}, "o": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 3.872983346207417}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 3.872983346207417}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.4142135623730951}}, "df": 5, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 4}}, "s": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 5}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}, "e": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}}, "df": 3, "s": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}}, "df": 1}, "d": {"docs": {"controlpi_plugins.state": {"tf": 2.6457513110645907}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndState": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrState": {"tf": 2.23606797749979}, "controlpi_plugins.state.AndSet": {"tf": 2.23606797749979}, "controlpi_plugins.state.OrSet": {"tf": 2}}, "df": 7}}}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 2, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 3}}}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 2}}}}}}}, "s": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 2, "y": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}}, "df": 6, "s": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}}, "df": 3}}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 3.3166247903554}, "controlpi_plugins.state.State": {"tf": 2.449489742783178}, "controlpi_plugins.state.StateAlias": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndState": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrState": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndSet": {"tf": 3.3166247903554}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 3}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 2}}, "df": 12, "u": {"docs": {}, "df": 0, "p": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 4}}, "s": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Execute": {"tf": 1}}, "df": 3}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 2}}}, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message.setdefault": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2.6457513110645907}}, "df": 2}}}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {"controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 2}}}}}, "c": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 2}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init": {"tf": 2.23606797749979}, "controlpi_plugins.util.Execute": {"tf": 2}, "controlpi_plugins.util.Alias": {"tf": 2.449489742783178}}, "df": 6, "s": {"docs": {"controlpi_plugins.wait": {"tf": 2}, "controlpi_plugins.wait.Wait": {"tf": 2}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 2.6457513110645907}, "controlpi_plugins.wait.Timer": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 8}}}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send": {"tf": 2}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 15, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.run": {"tf": 1.7320508075688772}, "controlpi.test": {"tf": 2.449489742783178}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.messagebus": {"tf": 3.605551275463989}, "controlpi.messagebus.Message": {"tf": 4.795831523312719}, "controlpi.messagebus.Message.__init__": {"tf": 2.6457513110645907}, "controlpi.messagebus.Message.update": {"tf": 2.8284271247461903}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.check": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus": {"tf": 4}, "controlpi.messagebus.MessageBus.send": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2.6457513110645907}, "controlpi_plugins.state": {"tf": 3.872983346207417}, "controlpi_plugins.state.State": {"tf": 3}, "controlpi_plugins.state.StateAlias": {"tf": 3.605551275463989}, "controlpi_plugins.state.AndState": {"tf": 3.605551275463989}, "controlpi_plugins.state.OrState": {"tf": 3.4641016151377544}, "controlpi_plugins.state.AndSet": {"tf": 4.358898943540674}, "controlpi_plugins.state.OrSet": {"tf": 3.7416573867739413}, "controlpi_plugins.util": {"tf": 3.1622776601683795}, "controlpi_plugins.util.Log": {"tf": 2.449489742783178}, "controlpi_plugins.util.Init": {"tf": 2.449489742783178}, "controlpi_plugins.util.Execute": {"tf": 2.23606797749979}, "controlpi_plugins.util.Alias": {"tf": 3.1622776601683795}, "controlpi_plugins.util.Counter": {"tf": 4.47213595499958}, "controlpi_plugins.util.Date": {"tf": 2.449489742783178}, "controlpi_plugins.wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 2.23606797749979}, "controlpi_plugins.wait.Timer": {"tf": 3}, "controlpi_plugins.wait.Periodic": {"tf": 1.7320508075688772}}, "df": 33}}, "s": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 2.8284271247461903}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.util": {"tf": 2.23606797749979}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 2}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 17}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 6}}}}, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 2}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}}, "df": 8}}, "l": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.baseplugin": {"tf": 4.47213595499958}, "controlpi.baseplugin.BasePlugin": {"tf": 2.8284271247461903}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}}, "df": 3}}, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}}, "df": 1}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}}, "df": 1}}}}}}, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 6}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 2}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Counter": {"tf": 2.23606797749979}}, "df": 1}}}, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1}}}}}}}, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2}}, "df": 4, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin": {"tf": 2}, "controlpi.baseplugin.BasePlugin": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 3}}}}}}}, "c": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}}, "df": 1}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}}, "df": 4}}}}}}, "t": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "p": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 3}}, "r": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 2.6457513110645907}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait": {"tf": 1.7320508075688772}}, "df": 26, "s": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 3}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 9.055385138137417}, "controlpi_plugins.state.State": {"tf": 6.082762530298219}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 6.244997998398398}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 6.164414002968976}, "controlpi_plugins.state.OrState": {"tf": 6.082762530298219}, "controlpi_plugins.state.AndSet": {"tf": 7.937253933193772}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 7.14142842854285}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 11, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state": {"tf": 3.3166247903554}, "controlpi_plugins.state.StateAlias": {"tf": 3.4641016151377544}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}}, "s": {"docs": {"controlpi_plugins.state": {"tf": 2}, "controlpi_plugins.state.AndState": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 2.23606797749979}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 2.23606797749979}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 9}}}, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 3.1622776601683795}}, "df": 1, "u": {"docs": {}, "df": 0, "p": {"docs": {"controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init.run": {"tf": 1}}, "df": 3}}, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 1}}}}}, "d": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 2}}}}}, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.baseplugin": {"tf": 2.449489742783178}, "controlpi.baseplugin.BasePlugin": {"tf": 2}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 23, "s": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}}, "df": 4}}}}}}, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 7}}}, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait.Wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 1.7320508075688772}}, "df": 2}}}}, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "m": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1.7320508075688772}}, "df": 1}}}, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}}, "df": 2}}}, "u": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}, "b": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 3}}}}}}}}}}, "o": {"docs": {}, "df": 0, "f": {"docs": {"controlpi": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 3}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 3.4641016151377544}, "controlpi.messagebus.Message": {"tf": 2}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.util": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 2}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 41, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}, "n": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1.7320508075688772}, "controlpi.test": {"tf": 1.7320508075688772}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util": {"tf": 2}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}}, "df": 12, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}}, "df": 4}, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 5}}, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Init": {"tf": 1}}, "df": 1}}}, "r": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 12, "i": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.Message": {"tf": 1}}, "df": 1}}}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}}, "df": 1}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 3}, "controlpi_plugins.state.OrState": {"tf": 3.1622776601683795}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 2}, "controlpi_plugins.state.OrSet": {"tf": 3}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}, "b": {"docs": {}, "df": 0, "j": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 10, "s": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 4}}}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 2}}}, "e": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 4}}}}, "w": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.Message": {"tf": 1.4142135623730951}}, "df": 1}}}}}}}}}}, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}}, "df": 7, "w": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}}}}}}}, "k": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}}, "df": 1}}}, "w": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1, "p": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}}, "df": 5}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 1}}}}}}}}}}, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 5}}}}}}}, "l": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.util.Alias": {"tf": 3.4641016151377544}}, "df": 1}}}, "m": {"docs": {"controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 3.4641016151377544}, "controlpi.messagebus.Message.__init__": {"tf": 2}, "controlpi.messagebus.Message.update": {"tf": 3}, "controlpi.messagebus.Message.setdefault": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 4.898979485566356}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 11, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 2.449489742783178}, "controlpi.test": {"tf": 3.605551275463989}, "controlpi.baseplugin": {"tf": 3.1622776601683795}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 3.872983346207417}, "controlpi.messagebus.Message": {"tf": 3}, "controlpi.messagebus.Message.__init__": {"tf": 2}, "controlpi.messagebus.Message.check_value": {"tf": 3.7416573867739413}, "controlpi.messagebus.Message.update": {"tf": 2.8284271247461903}, "controlpi.messagebus.Message.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageTemplate.check": {"tf": 4.242640687119285}, "controlpi.messagebus.TemplateRegistry": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 3.1622776601683795}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2.23606797749979}, "controlpi_plugins.state": {"tf": 2.8284271247461903}, "controlpi_plugins.util": {"tf": 2.23606797749979}, "controlpi_plugins.util.Log": {"tf": 4.47213595499958}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 3}, "controlpi_plugins.util.Execute": {"tf": 2.449489742783178}, "controlpi_plugins.util.Alias": {"tf": 4.58257569495584}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1.4142135623730951}}, "df": 39, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 2.23606797749979}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 11}}}, "s": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 2.449489742783178}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 3.1622776601683795}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 2.8284271247461903}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.util": {"tf": 2.23606797749979}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 3.1622776601683795}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init.run": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 3.3166247903554}, "controlpi_plugins.util.Alias": {"tf": 2.23606797749979}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 22, "[": {"0": {"docs": {"controlpi_plugins.util.Init": {"tf": 1}}, "df": 1}, "docs": {}, "df": 0}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 3}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.register": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 2}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2}}, "df": 12}}}}}}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.validate": {"tf": 1}}, "df": 1}}}}}}}}}}, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 3, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 2}}}}, "o": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1.7320508075688772}}, "df": 1, "s": {"docs": {"controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 3}}}}, "i": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 2}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 6}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.run": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 11, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.run": {"tf": 1}}, "df": 1}}}}, "n": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}}}}}, "y": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 4, "s": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}}}}, "t": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}}, "df": 3, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 4}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 7}}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi": {"tf": 1}, "controlpi.test": {"tf": 1}}, "df": 2}}}}}, "g": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin": {"tf": 2}}, "df": 1}}}}, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}}, "df": 4}}, "l": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}}}}}}, "b": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1.4142135623730951}, "controlpi.test": {"tf": 2.6457513110645907}, "controlpi.baseplugin": {"tf": 5.477225575051661}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 4.58257569495584}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 4.69041575982343}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.register": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.unregister": {"tf": 2}, "controlpi.messagebus.MessageBus.run": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus.send": {"tf": 3.3166247903554}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 3.3166247903554}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 33, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}}, "df": 1}}}}}}, "e": {"docs": {}, "df": 0, "x": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 2}}}}}}}}}}, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 10}}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 6, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 2}, "controlpi.pluginregistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 2}}, "df": 6}}}}}}, "d": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}}, "df": 5}}, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1}}}, "c": {"docs": {}, "df": 0, "k": {"docs": {"controlpi_plugins.wait.GenericWait": {"tf": 1}}, "df": 1}}}, "y": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2.449489742783178}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 2}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 2.6457513110645907}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 22, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1}}}}, "o": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi": {"tf": 1}, "controlpi.test": {"tf": 1}}, "df": 2}}}}}}}}}, "o": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 1, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}}, "df": 3, "s": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1}}, "df": 2}}}}}}, "t": {"docs": {}, "df": 0, "h": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 2}}}, "e": {"docs": {"controlpi.test": {"tf": 1.7320508075688772}, "controlpi.baseplugin": {"tf": 2.449489742783178}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.Message": {"tf": 2}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 30, "t": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "f": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 5}}}}, "h": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "k": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 1}}}}}}}}, "r": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 4.358898943540674}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2.23606797749979}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 3.7416573867739413}}, "df": 7, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.pluginregistry": {"tf": 3}, "controlpi.pluginregistry.PluginRegistry": {"tf": 3}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 2}}, "df": 6}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 4, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.register": {"tf": 2}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 26, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.TemplateRegistry": {"tf": 2.449489742783178}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2.8284271247461903}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 27}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1}}}}}}}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 2}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.register": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 1}}, "df": 5, "s": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 2.6457513110645907}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 16}, "d": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 4}, "r": {"docs": {"controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 2.6457513110645907}}, "df": 2}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 5}}}}}, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}}, "df": 5}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}}, "df": 2}}}}}}}}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}}, "t": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}}, "df": 5}, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}}, "df": 2}}}}}, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}, "l": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 20}}}}}}, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}}, "df": 1}, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 2, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 2}}}}}}}}}, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Counter": {"tf": 2.449489742783178}}, "df": 1}}}, "t": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2, "s": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}}, "df": 1}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1}}}}}}, "p": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}}, "df": 1, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}}}}}, "u": {"docs": {}, "df": 0, "n": {"docs": {"controlpi": {"tf": 1.4142135623730951}, "controlpi.run": {"tf": 2.8284271247461903}, "controlpi.test": {"tf": 1.7320508075688772}, "controlpi.baseplugin": {"tf": 3.4641016151377544}, "controlpi.baseplugin.BasePlugin": {"tf": 2.23606797749979}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 2.23606797749979}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 49, "n": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}}, "df": 2}}}}}}, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}}, "df": 2, "s": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}}, "df": 1}}}}}}, "a": {"docs": {"controlpi": {"tf": 1.7320508075688772}, "controlpi.run": {"tf": 2}, "controlpi.baseplugin": {"tf": 2.8284271247461903}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 3.872983346207417}, "controlpi.messagebus.Message": {"tf": 2}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 2.449489742783178}, "controlpi.messagebus.Message.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.TemplateRegistry": {"tf": 3}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 4}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 3.4641016151377544}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 2.6457513110645907}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 41, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}}, "df": 14, "d": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1.7320508075688772}, "controlpi.test": {"tf": 2.449489742783178}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 3.1622776601683795}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 3}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 2.23606797749979}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 2.6457513110645907}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1.4142135623730951}}, "df": 31, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 2.8284271247461903}, "controlpi_plugins.state.AndState": {"tf": 3.3166247903554}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndSet": {"tf": 3.605551275463989}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}, "y": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 8}, "o": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}}, "df": 2}}}}}}, "b": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 3}}}}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.state.State.process_conf": {"tf": 1}, "controlpi_plugins.state.StateAlias.process_conf": {"tf": 1}, "controlpi_plugins.state.AndState.process_conf": {"tf": 1}, "controlpi_plugins.state.OrState.process_conf": {"tf": 1}, "controlpi_plugins.state.AndSet.process_conf": {"tf": 1}, "controlpi_plugins.state.OrSet.process_conf": {"tf": 1}, "controlpi_plugins.util.Log.process_conf": {"tf": 1}, "controlpi_plugins.util.Init.process_conf": {"tf": 1}, "controlpi_plugins.util.Execute.process_conf": {"tf": 1}, "controlpi_plugins.util.Alias.process_conf": {"tf": 1}, "controlpi_plugins.util.Counter.process_conf": {"tf": 1}, "controlpi_plugins.util.Date.process_conf": {"tf": 1}, "controlpi_plugins.wait.Wait.process_conf": {"tf": 1}, "controlpi_plugins.wait.GenericWait.process_conf": {"tf": 1}, "controlpi_plugins.wait.Timer.process_conf": {"tf": 1}, "controlpi_plugins.wait.Periodic.process_conf": {"tf": 1}}, "df": 26, "y": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.449489742783178}, "controlpi.baseplugin.BasePlugin": {"tf": 2.23606797749979}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 11, "i": {"docs": {}, "df": 0, "o": {"docs": {"controlpi.run": {"tf": 2}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 3}, "controlpi.baseplugin.BasePlugin": {"tf": 2}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send": {"tf": 2}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 2.23606797749979}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 31}}, "h": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 2}}}}}}}}}}, "s": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 1.4142135623730951}, "controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.messagebus": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 7}}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 21, "o": {"docs": {}, "df": 0, "w": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1, "s": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 2}, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 3}}}}}, "s": {"docs": {}, "df": 0, "o": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}}, "df": 11}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}}, "df": 4}}}}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "y": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1.7320508075688772}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util": {"tf": 3.1622776601683795}, "controlpi_plugins.util.Alias": {"tf": 5}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 6, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}}}}, "d": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1}}}}}, "g": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 3, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 7}}}}}}, "t": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}}, "df": 7}, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.check_value": {"tf": 3}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 2.23606797749979}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 18}, "b": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 7}}}}}}}, "g": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.Message": {"tf": 1}}, "df": 1}}}}}}, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1}}, "df": 7}}}}, "c": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}}}}}}}, "f": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 7, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}}}}}, "v": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 1}}}}}}}}, "p": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "w": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"controlpi": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}}, "df": 9}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 29}}}}}}}, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 2}}}, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}}, "df": 5}, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 4}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {"controlpi": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 2.449489742783178}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.__init__": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 3.1622776601683795}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.7320508075688772}, "controlpi_plugins.wait": {"tf": 1}}, "df": 18, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}}, "df": 4}}}}, "c": {"docs": {}, "df": 0, "h": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}, "l": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}}, "df": 1}}}, "o": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1.4142135623730951}}, "df": 1}}}}, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 2}}, "df": 3}, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}}, "df": 2, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}, "s": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}}, "df": 1}, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait": {"tf": 4.47213595499958}, "controlpi_plugins.wait.Wait": {"tf": 5}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1.4142135623730951}, "controlpi_plugins.wait.GenericWait": {"tf": 4}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 8, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "/": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.wait": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "s": {"docs": {"controlpi_plugins.wait": {"tf": 1.4142135623730951}}, "df": 1}}}}}, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 1}}, "df": 7, "d": {"docs": {"controlpi": {"tf": 1}, "controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}}, "df": 8}, "f": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}}, "df": 4}}}}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"controlpi": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}}, "df": 2}}}}}}, "n": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}}, "df": 3, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}}}}}}, "i": {"docs": {}, "df": 0, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 2}}}}, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {"controlpi_plugins.util.Counter": {"tf": 2.23606797749979}}, "df": 1}}}}, "p": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 1, "d": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.23606797749979}}, "df": 2}}}}}}, "g": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1, "i": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.__init__": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.4142135623730951}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1.4142135623730951}}, "df": 16}}}}, "t": {"docs": {"controlpi.run": {"tf": 2.449489742783178}, "controlpi.test": {"tf": 2.449489742783178}, "controlpi.baseplugin": {"tf": 4.898979485566356}, "controlpi.baseplugin.BasePlugin": {"tf": 5.291502622129181}, "controlpi.messagebus": {"tf": 4.898979485566356}, "controlpi.messagebus.Message": {"tf": 6}, "controlpi.messagebus.Message.__init__": {"tf": 3.4641016151377544}, "controlpi.messagebus.Message.check_value": {"tf": 6.48074069840786}, "controlpi.messagebus.Message.update": {"tf": 5.196152422706632}, "controlpi.messagebus.Message.setdefault": {"tf": 4.242640687119285}, "controlpi.messagebus.MessageTemplate": {"tf": 3.872983346207417}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 4.242640687119285}, "controlpi.messagebus.MessageTemplate.update": {"tf": 5.744562646538029}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 4.58257569495584}, "controlpi.messagebus.MessageTemplate.check": {"tf": 7.937253933193772}, "controlpi.messagebus.TemplateRegistry": {"tf": 7.54983443527075}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 4.242640687119285}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 4.898979485566356}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 3.872983346207417}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 3.4641016151377544}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 6.48074069840786}, "controlpi.messagebus.MessageBus": {"tf": 3.872983346207417}, "controlpi.messagebus.MessageBus.__init__": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus.register": {"tf": 3}, "controlpi.messagebus.MessageBus.unregister": {"tf": 3}, "controlpi.messagebus.MessageBus.run": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageBus.send": {"tf": 3}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 3}, "controlpi.pluginregistry": {"tf": 5.385164807134504}, "controlpi.pluginregistry.PluginRegistry": {"tf": 4.795831523312719}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 4.123105625617661}, "controlpi_plugins.state": {"tf": 3}, "controlpi_plugins.state.State": {"tf": 3}, "controlpi_plugins.state.StateAlias": {"tf": 3}, "controlpi_plugins.state.AndState": {"tf": 3}, "controlpi_plugins.state.OrState": {"tf": 3}, "controlpi_plugins.state.AndSet": {"tf": 3}, "controlpi_plugins.state.OrSet": {"tf": 3}, "controlpi_plugins.util": {"tf": 2.449489742783178}, "controlpi_plugins.util.Log": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Init": {"tf": 3.4641016151377544}, "controlpi_plugins.util.Execute": {"tf": 2.449489742783178}, "controlpi_plugins.util.Alias": {"tf": 4.242640687119285}, "controlpi_plugins.util.Counter": {"tf": 2.449489742783178}, "controlpi_plugins.util.Date": {"tf": 3}, "controlpi_plugins.wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Timer": {"tf": 2.449489742783178}, "controlpi_plugins.wait.Periodic": {"tf": 2.449489742783178}}, "df": 52}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.register_schema": {"tf": 1}}, "df": 2}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.get_callbacks": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 2.23606797749979}, "controlpi_plugins.state.State": {"tf": 2.23606797749979}, "controlpi_plugins.state.StateAlias": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndState": {"tf": 2.23606797749979}, "controlpi_plugins.state.OrState": {"tf": 2.23606797749979}, "controlpi_plugins.state.AndSet": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrSet": {"tf": 2}, "controlpi_plugins.util.Counter": {"tf": 3}, "controlpi_plugins.util.Date": {"tf": 2.6457513110645907}}, "df": 16, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 11}}, "n": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi.pluginregistry": {"tf": 1.4142135623730951}}, "df": 1, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.wait": {"tf": 3}, "controlpi_plugins.wait.GenericWait": {"tf": 3.3166247903554}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 3}}}}}}}}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "o": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus.send": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.7320508075688772}}, "df": 2}}}, "l": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 2}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 1}}}}}, "g": {"docs": {"controlpi.run": {"tf": 2}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi_plugins.util": {"tf": 2.449489742783178}, "controlpi_plugins.util.Log": {"tf": 3.872983346207417}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}}, "df": 6, "g": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageBus": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 3}, "d": {"docs": {"controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}}, "df": 2}}}, "s": {"docs": {"controlpi_plugins.util": {"tf": 1}}, "df": 1}}, "t": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}, "o": {"docs": {}, "df": 0, "p": {"docs": {"controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 2}, "controlpi_plugins.wait.Periodic.run": {"tf": 1}}, "df": 3}}, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Wait": {"tf": 2.449489742783178}, "controlpi_plugins.wait.GenericWait": {"tf": 1.7320508075688772}}, "df": 3}}}, "i": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 2}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 15, "s": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 4}}}, "k": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state": {"tf": 2.23606797749979}}, "df": 1}}}, "t": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.4142135623730951}}, "df": 4}, "a": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}}, "df": 6}}}, "e": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}, "n": {"docs": {"controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}}, "df": 2}, "a": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}}, "df": 2}}}}}, "j": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}}, "df": 3, "s": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.register_schema": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 12}}}, "u": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.state": {"tf": 1.7320508075688772}}, "df": 1}}}}, "d": {"docs": {"controlpi_plugins.util.Date": {"tf": 1}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.run": {"tf": 1}}, "df": 1}, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.pluginregistry": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 2}}}}}}}}}, "j": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrState": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1}}, "df": 3}}}}}}}}}, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 2, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}}, "df": 2}, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 2}}, "df": 3}}}}}}}}}}, "f": {"docs": {}, "df": 0, "f": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.pluginregistry": {"tf": 1}}, "df": 1, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}}}}}, "d": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}, "e": {"docs": {}, "df": 0, "f": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.8284271247461903}, "controlpi.baseplugin.BasePlugin": {"tf": 2.6457513110645907}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 11, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}}, "df": 6, "d": {"docs": {"controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}}, "df": 4}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1.4142135623730951}}, "df": 2}}, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi_plugins.util.Alias": {"tf": 1}}, "df": 1}}}}}}}, "a": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "t": {"docs": {"controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}, "v": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "b": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}}}}, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "g": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 1}}}}}}}}}}}}, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1}}, "c": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}}, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}, "e": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1.4142135623730951}}, "df": 2}}}}, "s": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.state": {"tf": 1}}, "df": 1}}}}}}}, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}}, "df": 2}}}}}}}, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.util": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}}, "df": 3}}}}}, "o": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 29}}}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}}, "df": 2}}}, "n": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 4}}, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}}, "df": 4}}}, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "a": {"docs": {"controlpi.test": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}}, "df": 4}, "e": {"docs": {"controlpi_plugins.util.Date": {"tf": 5.477225575051661}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 2, "t": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}}}, "u": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}}, "df": 1}}}}, "e": {"docs": {"controlpi_plugins.state": {"tf": 1.7320508075688772}}, "df": 1}}, "y": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {"controlpi.messagebus": {"tf": 1}}, "df": 1, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 2}}}}}}}}}}}, "q": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 5.830951894845301}, "controlpi.test": {"tf": 5.830951894845301}, "controlpi.baseplugin": {"tf": 2.8284271247461903}, "controlpi.baseplugin.BasePlugin": {"tf": 2.8284271247461903}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.TemplateRegistry": {"tf": 4.242640687119285}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry": {"tf": 2}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.4142135623730951}, "controlpi_plugins.state": {"tf": 11.661903789690601}, "controlpi_plugins.state.State": {"tf": 6.48074069840786}, "controlpi_plugins.state.StateAlias": {"tf": 7.211102550927978}, "controlpi_plugins.state.AndState": {"tf": 8.366600265340756}, "controlpi_plugins.state.OrState": {"tf": 8.366600265340756}, "controlpi_plugins.state.AndSet": {"tf": 9.38083151964686}, "controlpi_plugins.state.OrSet": {"tf": 8.94427190999916}, "controlpi_plugins.util": {"tf": 7.211102550927978}, "controlpi_plugins.util.Log": {"tf": 6.6332495807108}, "controlpi_plugins.util.Init": {"tf": 6.48074069840786}, "controlpi_plugins.util.Execute": {"tf": 6}, "controlpi_plugins.util.Alias": {"tf": 10.770329614269007}, "controlpi_plugins.util.Counter": {"tf": 8.366600265340756}, "controlpi_plugins.util.Date": {"tf": 5.656854249492381}, "controlpi_plugins.wait": {"tf": 6}, "controlpi_plugins.wait.Wait": {"tf": 5.656854249492381}, "controlpi_plugins.wait.GenericWait": {"tf": 5.830951894845301}, "controlpi_plugins.wait.Timer": {"tf": 6.928203230275509}, "controlpi_plugins.wait.Periodic": {"tf": 3.7416573867739413}}, "df": 33}}, "e": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1}}, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}}, "df": 2}, "s": {"docs": {"controlpi_plugins.util.Counter": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 6, "x": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.run": {"tf": 2.6457513110645907}, "controlpi.test": {"tf": 3.3166247903554}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 3}, "controlpi.messagebus.Message.__init__": {"tf": 2}, "controlpi.messagebus.Message.update": {"tf": 2.449489742783178}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 3.7416573867739413}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 15, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 2}}}}}, "c": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 1}}}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.4142135623730951}}, "df": 7, "i": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.run": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}}, "df": 7}, "a": {"docs": {}, "df": 0, "l": {"docs": {"controlpi.messagebus.Message": {"tf": 1}}, "df": 1}}}}}}}}}, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "u": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1.7320508075688772}, "controlpi_plugins.util": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 2.23606797749979}, "controlpi_plugins.util.Execute": {"tf": 4.242640687119285}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}}, "df": 5, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 2}, "s": {"docs": {"controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}}, "df": 2}}}}}}, "p": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}}, "df": 3}}}}}}}}}, "m": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry.__init__": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}}, "df": 8}}}}, "v": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 2, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 2.23606797749979}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi_plugins.state": {"tf": 3}, "controlpi_plugins.state.State": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1.7320508075688772}, "controlpi_plugins.state.AndState": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrState": {"tf": 2.23606797749979}, "controlpi_plugins.state.AndSet": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrSet": {"tf": 2.23606797749979}, "controlpi_plugins.util": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 2.8284271247461903}, "controlpi_plugins.wait.Wait": {"tf": 2.6457513110645907}, "controlpi_plugins.wait.GenericWait": {"tf": 2.23606797749979}, "controlpi_plugins.wait.Timer": {"tf": 2.8284271247461903}, "controlpi_plugins.wait.Periodic": {"tf": 1.4142135623730951}}, "df": 23, "s": {"docs": {"controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}}, "df": 4}}}, "r": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.test": {"tf": 1}}, "df": 1, "t": {"docs": {}, "df": 0, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 2}}}}}}}}}, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "h": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}}, "df": 4}}}, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}}, "df": 2}, "f": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}}, "df": 2}}}}}}}, "l": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}}, "df": 2}}, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}}, "df": 10}}}}}}, "e": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}}, "df": 3}}}}}}}, "r": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.ConfException": {"tf": 1}, "controlpi.messagebus.BusException": {"tf": 1}}, "df": 2}}}}}, "s": {"docs": {}, "df": 0, "p": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}}, "df": 1}}}}}}}}}}, "n": {"docs": {}, "df": 0, "o": {"docs": {"controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.State.run": {"tf": 1}, "controlpi_plugins.state.StateAlias.run": {"tf": 1}, "controlpi_plugins.state.AndState.run": {"tf": 1}, "controlpi_plugins.state.OrState.run": {"tf": 1}, "controlpi_plugins.state.AndSet.run": {"tf": 1}, "controlpi_plugins.state.OrSet.run": {"tf": 1}, "controlpi_plugins.util.Log.run": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.run": {"tf": 1}, "controlpi_plugins.util.Alias.run": {"tf": 1}, "controlpi_plugins.util.Counter.run": {"tf": 1}, "controlpi_plugins.util.Date.run": {"tf": 1}, "controlpi_plugins.wait.Wait.run": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait.run": {"tf": 1}, "controlpi_plugins.wait.Timer.run": {"tf": 1}}, "df": 17, "r": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "z": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.run": {"tf": 1}, "controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1}, "controlpi_plugins.state.OrSet": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Counter": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 1}}, "df": 29}}}}}}}, "t": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.check_value": {"tf": 2}, "controlpi.messagebus.Message.update": {"tf": 2.449489742783178}, "controlpi.messagebus.Message.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 1}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 1}, "controlpi_plugins.state": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log": {"tf": 2}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 2.23606797749979}}, "df": 17, "h": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.MessageBus.register": {"tf": 1}}, "df": 2}}}}}, "n": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 1, "e": {"docs": {"controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}}, "df": 4}}, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "t": {"docs": {"controlpi.messagebus.MessageBus.send_nowait": {"tf": 1.7320508075688772}}, "df": 1}}}}}, "a": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin": {"tf": 1.7320508075688772}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus": {"tf": 1.7320508075688772}, "controlpi.pluginregistry": {"tf": 2.23606797749979}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.7320508075688772}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1.7320508075688772}, "controlpi_plugins.state": {"tf": 1.4142135623730951}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}}, "df": 13, "s": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}}, "df": 7, "p": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "c": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.pluginregistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry.PluginRegistry.__init__": {"tf": 1}}, "df": 3}}}}}}}}, "e": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "o": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "k": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}, "w": {"docs": {"controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus.__init__": {"tf": 1}, "controlpi_plugins.state": {"tf": 3.1622776601683795}, "controlpi_plugins.state.State": {"tf": 2.449489742783178}, "controlpi_plugins.state.StateAlias": {"tf": 2.23606797749979}, "controlpi_plugins.state.AndState": {"tf": 2.449489742783178}, "controlpi_plugins.state.OrState": {"tf": 2.449489742783178}, "controlpi_plugins.state.AndSet": {"tf": 3.1622776601683795}, "controlpi_plugins.state.OrSet": {"tf": 2.8284271247461903}, "controlpi_plugins.util.Alias": {"tf": 2.449489742783178}}, "df": 11}, "s": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 1}}}}, "c": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "s": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1}}, "df": 1}}}}}}}}}}, "u": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {"controlpi.messagebus.MessageTemplate": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi_plugins.wait": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}}, "df": 10}}}}}}, "h": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "v": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin": {"tf": 1}, "controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.Message": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 8}}, "s": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin.process_conf": {"tf": 1}, "controlpi.messagebus": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi_plugins.util.Log": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.wait.GenericWait": {"tf": 1}}, "df": 11}, "r": {"docs": {}, "df": 0, "d": {"docs": {}, "df": 0, "w": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1}}}}}}}, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}, "controlpi.baseplugin.BasePlugin.run": {"tf": 1}, "controlpi.pluginregistry.PluginRegistry": {"tf": 1}, "controlpi_plugins.state": {"tf": 1}}, "df": 4}}}, "%": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, "%": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.util.Date": {"tf": 1}}, "df": 1}}}}, ":": {"docs": {}, "df": 0, "%": {"docs": {}, "df": 0, "m": {"docs": {}, "df": 0, ":": {"docs": {}, "df": 0, "%": {"docs": {}, "df": 0, "s": {"docs": {"controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 1}}}}}}}, "v": {"1": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 8.426149773176359}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1.7320508075688772}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 4.123105625617661}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 3}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2.449489742783178}}, "df": 6}, "2": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 6}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 1}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 2.8284271247461903}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2}}, "df": 6}, "docs": {"controlpi.baseplugin": {"tf": 1.4142135623730951}}, "df": 1, "a": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.test": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 3.4641016151377544}, "controlpi.messagebus.Message.update": {"tf": 2}, "controlpi.messagebus.Message.setdefault": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.check": {"tf": 2}, "controlpi_plugins.util.Log": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Init": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Alias": {"tf": 1.7320508075688772}}, "df": 11, "a": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 1}, "controlpi.messagebus.validate": {"tf": 1}, "controlpi.messagebus.MessageTemplate": {"tf": 1}}, "df": 3, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}, "controlpi.baseplugin.BasePlugin": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 3}, "s": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}}, "df": 1}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "g": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 1}}, "df": 1}}}}}, "i": {"docs": {}, "df": 0, "t": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.messagebus.Message.update": {"tf": 1}, "controlpi.messagebus.Message.setdefault": {"tf": 1}, "controlpi.messagebus.MessageTemplate.update": {"tf": 1}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 1}}, "df": 4}}}}}, "u": {"docs": {}, "df": 0, "e": {"docs": {"controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.Message": {"tf": 3.605551275463989}, "controlpi.messagebus.Message.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.check_value": {"tf": 4.47213595499958}, "controlpi.messagebus.Message.update": {"tf": 3.1622776601683795}, "controlpi.messagebus.Message.setdefault": {"tf": 2.6457513110645907}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 2}, "controlpi.messagebus.MessageTemplate.check": {"tf": 3}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 2}}, "df": 17, "s": {"docs": {"controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 1}}, "df": 8}}}}, "r": {"docs": {}, "df": 0, "i": {"docs": {}, "df": 0, "a": {"docs": {}, "df": 0, "b": {"docs": {}, "df": 0, "l": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "s": {"docs": {"controlpi.baseplugin.BasePlugin": {"tf": 1}}, "df": 1}}}}}}}}}, "k": {"1": {"docs": {"controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.TemplateRegistry": {"tf": 8.54400374531753}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 4.123105625617661}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 3}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2.8284271247461903}, "controlpi.messagebus.MessageBus": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.register": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus.unregister": {"tf": 1}, "controlpi.messagebus.MessageBus.send": {"tf": 2.23606797749979}, "controlpi.messagebus.MessageBus.send_nowait": {"tf": 2.23606797749979}}, "df": 12}, "2": {"docs": {"controlpi.messagebus.TemplateRegistry": {"tf": 8.48528137423857}, "controlpi.messagebus.TemplateRegistry.insert": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.delete": {"tf": 2}, "controlpi.messagebus.TemplateRegistry.check": {"tf": 4.123105625617661}, "controlpi.messagebus.TemplateRegistry.get": {"tf": 3}, "controlpi.messagebus.TemplateRegistry.get_templates": {"tf": 2.8284271247461903}}, "df": 6}, "docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "y": {"docs": {"controlpi.baseplugin": {"tf": 2.6457513110645907}, "controlpi.baseplugin.BasePlugin": {"tf": 3.4641016151377544}, "controlpi.messagebus": {"tf": 2.23606797749979}, "controlpi.messagebus.Message": {"tf": 3.7416573867739413}, "controlpi.messagebus.Message.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.Message.check_value": {"tf": 1}, "controlpi.messagebus.Message.update": {"tf": 3.1622776601683795}, "controlpi.messagebus.Message.setdefault": {"tf": 2.449489742783178}, "controlpi.messagebus.MessageTemplate": {"tf": 3.1622776601683795}, "controlpi.messagebus.MessageTemplate.__init__": {"tf": 1.7320508075688772}, "controlpi.messagebus.MessageTemplate.from_message": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.update": {"tf": 5.291502622129181}, "controlpi.messagebus.MessageTemplate.setdefault": {"tf": 3.4641016151377544}, "controlpi.messagebus.MessageTemplate.check": {"tf": 5.744562646538029}, "controlpi.messagebus.TemplateRegistry": {"tf": 1}, "controlpi.messagebus.MessageBus": {"tf": 2}, "controlpi.messagebus.MessageBus.register": {"tf": 1}, "controlpi_plugins.state.State": {"tf": 1}, "controlpi_plugins.state.StateAlias": {"tf": 1}, "controlpi_plugins.state.StateAlias.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndState": {"tf": 1}, "controlpi_plugins.state.AndState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrState": {"tf": 1}, "controlpi_plugins.state.OrState.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet": {"tf": 1.4142135623730951}, "controlpi_plugins.state.OrSet": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Log": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Log.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Init": {"tf": 1.7320508075688772}, "controlpi_plugins.util.Init.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 3}, "controlpi_plugins.util.Counter.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Date": {"tf": 1.4142135623730951}, "controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Wait": {"tf": 1}, "controlpi_plugins.wait.Wait.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Timer": {"tf": 1}, "controlpi_plugins.wait.Timer.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.wait.Periodic": {"tf": 2.23606797749979}, "controlpi_plugins.wait.Periodic.CONF_SCHEMA": {"tf": 1}}, "df": 41, "s": {"docs": {"controlpi.messagebus": {"tf": 2}, "controlpi.messagebus.Message": {"tf": 1.4142135623730951}, "controlpi.messagebus.Message.check_value": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageTemplate.check": {"tf": 1}, "controlpi.messagebus.TemplateRegistry": {"tf": 1.4142135623730951}, "controlpi.messagebus.MessageBus": {"tf": 1}, "controlpi.pluginregistry": {"tf": 1}, "controlpi_plugins.state.State.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.AndSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.state.OrSet.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Execute.CONF_SCHEMA": {"tf": 1}, "controlpi_plugins.util.Alias": {"tf": 2}, "controlpi_plugins.util.Alias.CONF_SCHEMA": {"tf": 1.7320508075688772}, "controlpi_plugins.wait.GenericWait": {"tf": 1}, "controlpi_plugins.wait.GenericWait.CONF_SCHEMA": {"tf": 1}}, "df": 16}}}, "i": {"docs": {}, "df": 0, "n": {"docs": {}, "df": 0, "d": {"docs": {"controlpi.baseplugin": {"tf": 1}}, "df": 1, "s": {"docs": {"controlpi_plugins.state": {"tf": 1}, "controlpi_plugins.util": {"tf": 1}, "controlpi_plugins.util.Execute": {"tf": 1}, "controlpi_plugins.wait": {"tf": 1}}, "df": 4}}}}}, "z": {"docs": {}, "df": 0, "e": {"docs": {}, "df": 0, "r": {"docs": {}, "df": 0, "o": {"docs": {"controlpi.messagebus.MessageTemplate.check": {"tf": 1.4142135623730951}}, "df": 1}}}}, "y": {"docs": {"controlpi_plugins.util.Date.CONF_SCHEMA": {"tf": 1}}, "df": 1, "%": {"docs": {}, "df": 0, "m": {"docs": {"controlpi_plugins.util.Date": {"tf": 1}}, "df": 1}}}}}}, "pipeline": ["trimmer"], "_isPrebuiltIndex": true};
+
+    // mirrored in build-search-index.js (part 1)
+    // Also split on html tags. this is a cheap heuristic, but good enough.
+    elasticlunr.tokenizer.setSeperator(/[\s\-.;&_'"=,()]+|<[^>]*>/);
+
+    let searchIndex;
+    if (docs._isPrebuiltIndex) {
+        console.info("using precompiled search index");
+        searchIndex = elasticlunr.Index.load(docs);
+    } else {
+        console.time("building search index");
+        // mirrored in build-search-index.js (part 2)
+        searchIndex = elasticlunr(function () {
+            this.pipeline.remove(elasticlunr.stemmer);
+            this.pipeline.remove(elasticlunr.stopWordFilter);
+            this.addField("qualname");
+            this.addField("fullname");
+            this.addField("annotation");
+            this.addField("default_value");
+            this.addField("signature");
+            this.addField("bases");
+            this.addField("doc");
+            this.setRef("fullname");
+        });
+        for (let doc of docs) {
+            searchIndex.addDoc(doc);
+        }
+        console.timeEnd("building search index");
+    }
+
+    return (term) => searchIndex.search(term, {
+        fields: {
+            qualname: {boost: 4},
+            fullname: {boost: 2},
+            annotation: {boost: 2},
+            default_value: {boost: 2},
+            signature: {boost: 2},
+            bases: {boost: 2},
+            doc: {boost: 1},
+        },
+        expand: true
+    });
+})();
\ No newline at end of file
diff --git a/doc/controlpi/baseplugin.html b/doc/controlpi/baseplugin.html
deleted file mode 100644 (file)
index 7f2f42f..0000000
+++ /dev/null
@@ -1,621 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi.baseplugin API documentation</title>
-<meta name="description" content="Define base class for all ControlPi plugins …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Module <code>controlpi.baseplugin</code></h1>
-</header>
-<section id="section-intro">
-<p>Define base class for all ControlPi plugins.</p>
-<p>The class BasePlugin provides the abstract base class for concrete plugins
-running on the ControlPi system.</p>
-<p>It has three abstract methods that have to be implemented by all concrete
-plugins:
-- The class property CONF_SCHEMA is the JSON schema of the configuration of
-the plugin. The configuration read from the global configuration file is
-checked against this schema during initialisation.
-- The method process_conf is called at the end of initialisation and is used
-to initialise the plugin. It can be assumed that self.bus is the message
-bus of the system, self.name the instance name, and self.conf the
-configuration already validated against the schema.
-- The run coroutines of all plugins are executed concurrently by the main
-system.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class TestPlugin(BasePlugin):
-...     CONF_SCHEMA = {'properties': {'key': {'type': 'string'}},
-...                    'required': ['key']}
-...     def process_conf(self):
-...         if 'key' in self.conf:
-...             print(f&quot;Processing '{self.conf['key']}'.&quot;)
-...     async def run(self):
-...         print(&quot;Doing something else.&quot;)
-</code></pre>
-<p>Plugins are configured and run based on the information in the global
-configuration. Here, we test this manually:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def test():
-...     p = TestPlugin(MessageBus(), 'Test Instance', {'key': 'Something'})
-...     await p.run()
-&gt;&gt;&gt; asyncio.run(test())
-Processing 'Something'.
-Doing something else.
-</code></pre>
-<p>Each plugin gets a reference to the system message bus during
-initialisation, which can be accessed as self.bus in the functions of the
-plugin class. This can be used to register and unregister message bus
-clients:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class BusPlugin(BasePlugin):
-...     CONF_SCHEMA = True
-...     async def receive(self, message):
-...         print(f&quot;{self.name} received {message}.&quot;)
-...         await self.bus.send({'sender': self.name, 'event': 'Receive'})
-...     def process_conf(self):
-...         self.bus.register(self.name, 'BusPlugin',
-...                           [{'event': {'type': 'string'}}],
-...                           [{'target': {'const': self.name}}],
-...                           self.receive)
-...     async def run(self):
-...         await self.bus.send({'sender': self.name, 'event': 'Run'})
-</code></pre>
-<p>Again, we run this manually here, but this is done by the main coroutine
-when using the system in production:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def log(message):
-...     print(f&quot;Log: {message}&quot;)
-&gt;&gt;&gt; async def test_bus_plugin():
-...     bus = MessageBus()
-...     p = BusPlugin(bus, 'Bus Test', {})
-...     bus.register('Test', 'TestPlugin',
-...                  [{}], [{'sender': {'const': 'Bus Test'}}], log)
-...     bus_task = asyncio.create_task(bus.run())
-...     asyncio.create_task(p.run())
-...     await bus.send({'sender': 'Test', 'target': 'Bus Test', 'key': 'v'})
-...     await asyncio.sleep(0)
-...     await asyncio.sleep(0)
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(test_bus_plugin())
-Bus Test received {'sender': 'Test', 'target': 'Bus Test', 'key': 'v'}.
-Log: {'sender': 'Bus Test', 'event': 'Receive'}
-Log: {'sender': 'Bus Test', 'event': 'Run'}
-</code></pre>
-<p>Often, there will be a one-to-one correspondence between plugin
-instances and message bus clients, a plugin instance will be a message bus
-client. But there are also cases, where one plugin instance might register
-and unregister a lot of message bus clients, maybe even dynamically through
-its lifetime. A plugin for an input/output card might register separate
-clients for each pin of the card, a plugin for some kind of hardware bus
-might register separate clients for all devices connected to the bus, or a
-network socket plugin might register separate clients for all connections
-to the socket (and unregister them when the connection is closed).</p>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Define base class for all ControlPi plugins.
-
-The class BasePlugin provides the abstract base class for concrete plugins
-running on the ControlPi system.
-
-It has three abstract methods that have to be implemented by all concrete
-plugins:
-- The class property CONF_SCHEMA is the JSON schema of the configuration of
-  the plugin. The configuration read from the global configuration file is
-  checked against this schema during initialisation.
-- The method process_conf is called at the end of initialisation and is used
-  to initialise the plugin. It can be assumed that self.bus is the message
-  bus of the system, self.name the instance name, and self.conf the
-  configuration already validated against the schema.
-- The run coroutines of all plugins are executed concurrently by the main
-  system.
-&gt;&gt;&gt; class TestPlugin(BasePlugin):
-...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},
-...                    &#39;required&#39;: [&#39;key&#39;]}
-...     def process_conf(self):
-...         if &#39;key&#39; in self.conf:
-...             print(f&#34;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&#34;)
-...     async def run(self):
-...         print(&#34;Doing something else.&#34;)
-
-Plugins are configured and run based on the information in the global
-configuration. Here, we test this manually:
-&gt;&gt;&gt; async def test():
-...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;, {&#39;key&#39;: &#39;Something&#39;})
-...     await p.run()
-&gt;&gt;&gt; asyncio.run(test())
-Processing &#39;Something&#39;.
-Doing something else.
-
-Each plugin gets a reference to the system message bus during
-initialisation, which can be accessed as self.bus in the functions of the
-plugin class. This can be used to register and unregister message bus
-clients:
-&gt;&gt;&gt; class BusPlugin(BasePlugin):
-...     CONF_SCHEMA = True
-...     async def receive(self, message):
-...         print(f&#34;{self.name} received {message}.&#34;)
-...         await self.bus.send({&#39;sender&#39;: self.name, &#39;event&#39;: &#39;Receive&#39;})
-...     def process_conf(self):
-...         self.bus.register(self.name, &#39;BusPlugin&#39;,
-...                           [{&#39;event&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-...                           [{&#39;target&#39;: {&#39;const&#39;: self.name}}],
-...                           self.receive)
-...     async def run(self):
-...         await self.bus.send({&#39;sender&#39;: self.name, &#39;event&#39;: &#39;Run&#39;})
-
-Again, we run this manually here, but this is done by the main coroutine
-when using the system in production:
-&gt;&gt;&gt; async def log(message):
-...     print(f&#34;Log: {message}&#34;)
-&gt;&gt;&gt; async def test_bus_plugin():
-...     bus = MessageBus()
-...     p = BusPlugin(bus, &#39;Bus Test&#39;, {})
-...     bus.register(&#39;Test&#39;, &#39;TestPlugin&#39;,
-...                  [{}], [{&#39;sender&#39;: {&#39;const&#39;: &#39;Bus Test&#39;}}], log)
-...     bus_task = asyncio.create_task(bus.run())
-...     asyncio.create_task(p.run())
-...     await bus.send({&#39;sender&#39;: &#39;Test&#39;, &#39;target&#39;: &#39;Bus Test&#39;, &#39;key&#39;: &#39;v&#39;})
-...     await asyncio.sleep(0)
-...     await asyncio.sleep(0)
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(test_bus_plugin())
-Bus Test received {&#39;sender&#39;: &#39;Test&#39;, &#39;target&#39;: &#39;Bus Test&#39;, &#39;key&#39;: &#39;v&#39;}.
-Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Receive&#39;}
-Log: {&#39;sender&#39;: &#39;Bus Test&#39;, &#39;event&#39;: &#39;Run&#39;}
-
-Often, there will be a one-to-one correspondence between plugin
-instances and message bus clients, a plugin instance will be a message bus
-client. But there are also cases, where one plugin instance might register
-and unregister a lot of message bus clients, maybe even dynamically through
-its lifetime. A plugin for an input/output card might register separate
-clients for each pin of the card, a plugin for some kind of hardware bus
-might register separate clients for all devices connected to the bus, or a
-network socket plugin might register separate clients for all connections
-to the socket (and unregister them when the connection is closed).
-&#34;&#34;&#34;
-__pdoc__ = {&#39;BasePlugin.CONF_SCHEMA&#39;: False}
-
-from abc import ABC, abstractmethod
-import asyncio
-import jsonschema  # type: ignore
-
-from controlpi.messagebus import MessageBus
-
-from typing import Union, Dict, List, Any
-JSONSchema = Union[bool, Dict[str, Union[None, str, int, float, bool,
-                                         Dict[str, Any], List[Any]]]]
-# Could be more specific.
-PluginConf = Dict[str, Any]
-# Could be more specific.
-
-
-class ConfException(Exception):
-    &#34;&#34;&#34;Raise for errors in plugin configurations.&#34;&#34;&#34;
-
-
-class BasePlugin(ABC):
-    &#34;&#34;&#34;Base class for all ControlPi plugins.
-
-    &gt;&gt;&gt; class TestPlugin(BasePlugin):
-    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},
-    ...                    &#39;required&#39;: [&#39;key&#39;]}
-    ...     def process_conf(self):
-    ...         if &#39;key&#39; in self.conf:
-    ...             print(f&#34;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&#34;)
-    ...     async def run(self):
-    ...         print(&#34;Doing something else.&#34;)
-
-    Initialisation sets the instance variables bus to the given message bus,
-    name to the given name, and conf to the given configuration:
-    &gt;&gt;&gt; class TestPlugin(BasePlugin):
-    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},
-    ...                    &#39;required&#39;: [&#39;key&#39;]}
-    ...     def process_conf(self):
-    ...         if &#39;key&#39; in self.conf:
-    ...             print(f&#34;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&#34;)
-    ...     async def run(self):
-    ...         print(&#34;Doing something else.&#34;)
-    &gt;&gt;&gt; async def test():
-    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,
-    ...                    {&#39;key&#39;: &#39;Something&#39;})
-    ...     print(p.bus)
-    ...     print(p.name)
-    ...     print(p.conf)
-    &gt;&gt;&gt; asyncio.run(test())  # doctest: +ELLIPSIS
-    Processing &#39;Something&#39;.
-    &lt;controlpi.messagebus.MessageBus object at 0x...&gt;
-    Test Instance
-    {&#39;key&#39;: &#39;Something&#39;}
-
-    It also validates the configuration against the schema in CONF_SCHEMA
-    and raises ConfException if is not validated.
-    &gt;&gt;&gt; async def test():
-    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,
-    ...                    {&#39;key&#39;: 42})
-    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;
-    is not valid.
-    &gt;&gt;&gt; async def test():
-    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,
-    ...                    {&#39;key 2&#39;: &#39;Something&#39;})
-    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;
-    is not valid.
-
-    Finally, it calls process_conf, which is the function that should be
-    overridden by concrete plugins.
-    &#34;&#34;&#34;
-
-    @property
-    @classmethod
-    @abstractmethod
-    def CONF_SCHEMA(cls) -&gt; JSONSchema:
-        &#34;&#34;&#34;JSON schema for configuration of plugin.
-
-        Given configurations are validated against this schema in __init__.
-        process_conf and run can assume a valid configuration in self.conf.
-        &#34;&#34;&#34;
-        raise NotImplementedError
-
-    def __init__(self, bus: MessageBus, name: str, conf: PluginConf) -&gt; None:
-        assert isinstance(bus, MessageBus)
-        self.bus = bus
-        assert isinstance(name, str)
-        self.name = name
-        jsonschema.Draft7Validator.check_schema(type(self).CONF_SCHEMA)
-        validator = jsonschema.Draft7Validator(type(self).CONF_SCHEMA)
-        assert isinstance(conf, dict)
-        valid = True
-        for error in validator.iter_errors(conf):
-            print(error)
-            valid = False
-        if not valid:
-            raise ConfException(f&#34;Configuration for &#39;{self.name}&#39;&#34;
-                                &#34; is not valid.&#34;)
-        self.conf = conf
-        self.process_conf()
-
-    @abstractmethod
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Process the configuration.
-
-        Abstract method has to be overridden by concrete plugins.
-        process_conf is called at the end of initialisation after the bus
-        and the configuration are available as self.bus and self.conf, but
-        before any of the run coroutines are executed.
-        &#34;&#34;&#34;
-        raise NotImplementedError
-
-    @abstractmethod
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run the plugin.
-
-        The coroutine is run concurrently with the message bus and all
-        other plugins. Initial messages and other tasks can be done here.
-        It is also okay to run a plugin-specific infinite loop concurrently
-        with the rest of the system.
-        &#34;&#34;&#34;
-        raise NotImplementedError</code></pre>
-</details>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-classes">Classes</h2>
-<dl>
-<dt id="controlpi.baseplugin.ConfException"><code class="flex name class">
-<span>class <span class="ident">ConfException</span></span>
-<span>(</span><span>*args, **kwargs)</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Raise for errors in plugin configurations.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class ConfException(Exception):
-    &#34;&#34;&#34;Raise for errors in plugin configurations.&#34;&#34;&#34;</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li>builtins.Exception</li>
-<li>builtins.BaseException</li>
-</ul>
-</dd>
-<dt id="controlpi.baseplugin.BasePlugin"><code class="flex name class">
-<span>class <span class="ident">BasePlugin</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Base class for all ControlPi plugins.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class TestPlugin(BasePlugin):
-...     CONF_SCHEMA = {'properties': {'key': {'type': 'string'}},
-...                    'required': ['key']}
-...     def process_conf(self):
-...         if 'key' in self.conf:
-...             print(f&quot;Processing '{self.conf['key']}'.&quot;)
-...     async def run(self):
-...         print(&quot;Doing something else.&quot;)
-</code></pre>
-<p>Initialisation sets the instance variables bus to the given message bus,
-name to the given name, and conf to the given configuration:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class TestPlugin(BasePlugin):
-...     CONF_SCHEMA = {'properties': {'key': {'type': 'string'}},
-...                    'required': ['key']}
-...     def process_conf(self):
-...         if 'key' in self.conf:
-...             print(f&quot;Processing '{self.conf['key']}'.&quot;)
-...     async def run(self):
-...         print(&quot;Doing something else.&quot;)
-&gt;&gt;&gt; async def test():
-...     p = TestPlugin(MessageBus(), 'Test Instance',
-...                    {'key': 'Something'})
-...     print(p.bus)
-...     print(p.name)
-...     print(p.conf)
-&gt;&gt;&gt; asyncio.run(test())  # doctest: +ELLIPSIS
-Processing 'Something'.
-&lt;controlpi.messagebus.MessageBus object at 0x...&gt;
-Test Instance
-{'key': 'Something'}
-</code></pre>
-<p>It also validates the configuration against the schema in CONF_SCHEMA
-and raises ConfException if is not validated.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def test():
-...     p = TestPlugin(MessageBus(), 'Test Instance',
-...                    {'key': 42})
-&gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
-Traceback (most recent call last):
-  ...
-baseplugin.ConfException: Configuration for 'Test Instance'
-is not valid.
-&gt;&gt;&gt; async def test():
-...     p = TestPlugin(MessageBus(), 'Test Instance',
-...                    {'key 2': 'Something'})
-&gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
-Traceback (most recent call last):
-  ...
-baseplugin.ConfException: Configuration for 'Test Instance'
-is not valid.
-</code></pre>
-<p>Finally, it calls process_conf, which is the function that should be
-overridden by concrete plugins.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class BasePlugin(ABC):
-    &#34;&#34;&#34;Base class for all ControlPi plugins.
-
-    &gt;&gt;&gt; class TestPlugin(BasePlugin):
-    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},
-    ...                    &#39;required&#39;: [&#39;key&#39;]}
-    ...     def process_conf(self):
-    ...         if &#39;key&#39; in self.conf:
-    ...             print(f&#34;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&#34;)
-    ...     async def run(self):
-    ...         print(&#34;Doing something else.&#34;)
-
-    Initialisation sets the instance variables bus to the given message bus,
-    name to the given name, and conf to the given configuration:
-    &gt;&gt;&gt; class TestPlugin(BasePlugin):
-    ...     CONF_SCHEMA = {&#39;properties&#39;: {&#39;key&#39;: {&#39;type&#39;: &#39;string&#39;}},
-    ...                    &#39;required&#39;: [&#39;key&#39;]}
-    ...     def process_conf(self):
-    ...         if &#39;key&#39; in self.conf:
-    ...             print(f&#34;Processing &#39;{self.conf[&#39;key&#39;]}&#39;.&#34;)
-    ...     async def run(self):
-    ...         print(&#34;Doing something else.&#34;)
-    &gt;&gt;&gt; async def test():
-    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,
-    ...                    {&#39;key&#39;: &#39;Something&#39;})
-    ...     print(p.bus)
-    ...     print(p.name)
-    ...     print(p.conf)
-    &gt;&gt;&gt; asyncio.run(test())  # doctest: +ELLIPSIS
-    Processing &#39;Something&#39;.
-    &lt;controlpi.messagebus.MessageBus object at 0x...&gt;
-    Test Instance
-    {&#39;key&#39;: &#39;Something&#39;}
-
-    It also validates the configuration against the schema in CONF_SCHEMA
-    and raises ConfException if is not validated.
-    &gt;&gt;&gt; async def test():
-    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,
-    ...                    {&#39;key&#39;: 42})
-    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;
-    is not valid.
-    &gt;&gt;&gt; async def test():
-    ...     p = TestPlugin(MessageBus(), &#39;Test Instance&#39;,
-    ...                    {&#39;key 2&#39;: &#39;Something&#39;})
-    &gt;&gt;&gt; asyncio.run(test())  # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    baseplugin.ConfException: Configuration for &#39;Test Instance&#39;
-    is not valid.
-
-    Finally, it calls process_conf, which is the function that should be
-    overridden by concrete plugins.
-    &#34;&#34;&#34;
-
-    @property
-    @classmethod
-    @abstractmethod
-    def CONF_SCHEMA(cls) -&gt; JSONSchema:
-        &#34;&#34;&#34;JSON schema for configuration of plugin.
-
-        Given configurations are validated against this schema in __init__.
-        process_conf and run can assume a valid configuration in self.conf.
-        &#34;&#34;&#34;
-        raise NotImplementedError
-
-    def __init__(self, bus: MessageBus, name: str, conf: PluginConf) -&gt; None:
-        assert isinstance(bus, MessageBus)
-        self.bus = bus
-        assert isinstance(name, str)
-        self.name = name
-        jsonschema.Draft7Validator.check_schema(type(self).CONF_SCHEMA)
-        validator = jsonschema.Draft7Validator(type(self).CONF_SCHEMA)
-        assert isinstance(conf, dict)
-        valid = True
-        for error in validator.iter_errors(conf):
-            print(error)
-            valid = False
-        if not valid:
-            raise ConfException(f&#34;Configuration for &#39;{self.name}&#39;&#34;
-                                &#34; is not valid.&#34;)
-        self.conf = conf
-        self.process_conf()
-
-    @abstractmethod
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Process the configuration.
-
-        Abstract method has to be overridden by concrete plugins.
-        process_conf is called at the end of initialisation after the bus
-        and the configuration are available as self.bus and self.conf, but
-        before any of the run coroutines are executed.
-        &#34;&#34;&#34;
-        raise NotImplementedError
-
-    @abstractmethod
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run the plugin.
-
-        The coroutine is run concurrently with the message bus and all
-        other plugins. Initial messages and other tasks can be done here.
-        It is also okay to run a plugin-specific infinite loop concurrently
-        with the rest of the system.
-        &#34;&#34;&#34;
-        raise NotImplementedError</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li>abc.ABC</li>
-</ul>
-<h3>Subclasses</h3>
-<ul class="hlist">
-<li><a title="controlpi_plugins.state.AndState" href="../controlpi_plugins/state.html#controlpi_plugins.state.AndState">AndState</a></li>
-<li><a title="controlpi_plugins.state.OrState" href="../controlpi_plugins/state.html#controlpi_plugins.state.OrState">OrState</a></li>
-<li><a title="controlpi_plugins.state.State" href="../controlpi_plugins/state.html#controlpi_plugins.state.State">State</a></li>
-<li><a title="controlpi_plugins.state.StateAlias" href="../controlpi_plugins/state.html#controlpi_plugins.state.StateAlias">StateAlias</a></li>
-<li><a title="controlpi_plugins.util.Alias" href="../controlpi_plugins/util.html#controlpi_plugins.util.Alias">Alias</a></li>
-<li><a title="controlpi_plugins.util.Execute" href="../controlpi_plugins/util.html#controlpi_plugins.util.Execute">Execute</a></li>
-<li><a title="controlpi_plugins.util.Init" href="../controlpi_plugins/util.html#controlpi_plugins.util.Init">Init</a></li>
-<li><a title="controlpi_plugins.util.Log" href="../controlpi_plugins/util.html#controlpi_plugins.util.Log">Log</a></li>
-<li><a title="controlpi_plugins.wait.GenericWait" href="../controlpi_plugins/wait.html#controlpi_plugins.wait.GenericWait">GenericWait</a></li>
-<li><a title="controlpi_plugins.wait.Wait" href="../controlpi_plugins/wait.html#controlpi_plugins.wait.Wait">Wait</a></li>
-</ul>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi.baseplugin.BasePlugin.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Process the configuration.</p>
-<p>Abstract method has to be overridden by concrete plugins.
-process_conf is called at the end of initialisation after the bus
-and the configuration are available as self.bus and self.conf, but
-before any of the run coroutines are executed.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">@abstractmethod
-def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Process the configuration.
-
-    Abstract method has to be overridden by concrete plugins.
-    process_conf is called at the end of initialisation after the bus
-    and the configuration are available as self.bus and self.conf, but
-    before any of the run coroutines are executed.
-    &#34;&#34;&#34;
-    raise NotImplementedError</code></pre>
-</details>
-</dd>
-<dt id="controlpi.baseplugin.BasePlugin.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run the plugin.</p>
-<p>The coroutine is run concurrently with the message bus and all
-other plugins. Initial messages and other tasks can be done here.
-It is also okay to run a plugin-specific infinite loop concurrently
-with the rest of the system.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">@abstractmethod
-async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run the plugin.
-
-    The coroutine is run concurrently with the message bus and all
-    other plugins. Initial messages and other tasks can be done here.
-    It is also okay to run a plugin-specific infinite loop concurrently
-    with the rest of the system.
-    &#34;&#34;&#34;
-    raise NotImplementedError</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-</dl>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3>Super-module</h3>
-<ul>
-<li><code><a title="controlpi" href="index.html">controlpi</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-classes">Classes</a></h3>
-<ul>
-<li>
-<h4><code><a title="controlpi.baseplugin.ConfException" href="#controlpi.baseplugin.ConfException">ConfException</a></code></h4>
-</li>
-<li>
-<h4><code><a title="controlpi.baseplugin.BasePlugin" href="#controlpi.baseplugin.BasePlugin">BasePlugin</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi.baseplugin.BasePlugin.process_conf" href="#controlpi.baseplugin.BasePlugin.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi.baseplugin.BasePlugin.run" href="#controlpi.baseplugin.BasePlugin.run">run</a></code></li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi/index.html b/doc/controlpi/index.html
deleted file mode 100644 (file)
index d42fb6c..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi API documentation</title>
-<meta name="description" content="Provide the infrastructure for the ControlPi system …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Package <code>controlpi</code></h1>
-</header>
-<section id="section-intro">
-<p>Provide the infrastructure for the ControlPi system.</p>
-<p>The infrastructure consists of the message bus from module messagebus, the
-plugin registry from module pluginregistry and the abstract base plugin from
-module baseplugin.</p>
-<p>The package combines them in its run function, which is used by <strong>main</strong>.py
-to run a ControlPi system based on a configuration file indefinitely.</p>
-<p>The test function is a utility function to test plugins with minimal
-boilerplate code.</p>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Provide the infrastructure for the ControlPi system.
-
-The infrastructure consists of the message bus from module messagebus, the
-plugin registry from module pluginregistry and the abstract base plugin from
-module baseplugin.
-
-The package combines them in its run function, which is used by __main__.py
-to run a ControlPi system based on a configuration file indefinitely.
-
-The test function is a utility function to test plugins with minimal
-boilerplate code.
-&#34;&#34;&#34;
-import asyncio
-import jsonschema  # type: ignore
-
-from controlpi.messagebus import MessageBus, Message, MessageTemplate
-from controlpi.pluginregistry import PluginRegistry
-from controlpi.baseplugin import BasePlugin, PluginConf, ConfException
-
-from typing import Dict, List, Coroutine, Any
-
-
-CONF_SCHEMA = {&#39;type&#39;: &#39;object&#39;,
-               &#39;patternProperties&#39;: {&#39;.*&#39;: {&#39;type&#39;: &#39;object&#39;}}}
-
-
-def _process_conf(message_bus: MessageBus,
-                  conf: Dict[str, PluginConf]) -&gt; List[Coroutine]:
-    jsonschema.Draft7Validator.check_schema(CONF_SCHEMA)
-    validator = jsonschema.Draft7Validator(CONF_SCHEMA)
-    valid = True
-    for error in validator.iter_errors(conf):
-        print(error)
-        valid = False
-    if not valid:
-        return []
-    plugins = PluginRegistry(&#39;controlpi_plugins&#39;, BasePlugin)
-    coroutines = [message_bus.run()]
-    for instance_name in conf:
-        instance_conf = conf[instance_name]
-        if &#39;plugin&#39; not in instance_conf:
-            print(&#34;No plugin implementation specified for instance&#34;
-                  f&#34; &#39;{instance_name}&#39;.&#34;)
-            continue
-        plugin_name = instance_conf[&#39;plugin&#39;]
-        if plugin_name not in plugins:
-            print(f&#34;No implementation found for plugin &#39;{plugin_name}&#39;&#34;
-                  f&#34; (specified for instance &#39;{instance_name}&#39;).&#34;)
-            continue
-        plugin = plugins[plugin_name]
-        try:
-            instance = plugin(message_bus, instance_name, instance_conf)
-            coroutines.append(instance.run())
-        except ConfException as e:
-            print(e)
-            continue
-    return coroutines
-
-
-async def run(conf: Dict[str, PluginConf]) -&gt; None:
-    &#34;&#34;&#34;Run the ControlPi system based on a configuration.
-
-    Setup message bus, process given configuration, and run message bus and
-    plugins concurrently and indefinitely.
-
-    This function is mainly used by __main__.py to run a ControlPi system
-    based on a configuration loaded from a configuration JSON file on disk.
-
-    &gt;&gt;&gt; async def test_coroutine():
-    ...     conf = {&#34;Example Init&#34;:
-    ...             {&#34;plugin&#34;: &#34;Init&#34;,
-    ...              &#34;messages&#34;: [{&#34;id&#34;: 42,
-    ...                            &#34;content&#34;: &#34;Test Message&#34;},
-    ...                           {&#34;id&#34;: 42.42,
-    ...                            &#34;content&#34;: &#34;Second Message&#34;}]},
-    ...             &#34;Example Log&#34;:
-    ...             {&#34;plugin&#34;: &#34;Log&#34;,
-    ...              &#34;filter&#34;: [{&#34;sender&#34;: {&#34;const&#34;: &#34;Example Init&#34;}}]}}
-    ...     run_task = asyncio.create_task(run(conf))
-    ...     await asyncio.sleep(0.1)
-    ...     run_task.cancel()
-    &gt;&gt;&gt; asyncio.run(test_coroutine())  # doctest: +NORMALIZE_WHITESPACE
-    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,
-                  &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,
-                  &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-    &#34;&#34;&#34;
-    message_bus = MessageBus()
-    coroutines = _process_conf(message_bus, conf)
-    try:
-        await asyncio.gather(*coroutines)
-    except asyncio.exceptions.CancelledError:
-        pass
-
-
-async def test(conf: Dict[str, PluginConf],
-               messages: List[Dict[str, Any]],
-               wait: float = 0.0) -&gt; None:
-    &#34;&#34;&#34;Test configuration of ControlPi system.
-
-    Setup message bus, process given configuration, run message bus and
-    plugins concurrently, send given messages on message bus and print all
-    messages on message bus. Terminate when queue of message bus is empty.
-
-    This function allows to test single plugins or small plugin
-    configurations with minimal boilerplate code:
-    &gt;&gt;&gt; asyncio.run(test(
-    ...     {&#34;Example Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-    ...                       &#34;messages&#34;: [{&#34;id&#34;: 42,
-    ...                                     &#34;content&#34;: &#34;Test Message&#34;},
-    ...                                    {&#34;id&#34;: 42.42,
-    ...                                     &#34;content&#34;: &#34;Second Message&#34;}]}},
-    ...     [{&#34;target&#34;: &#34;Example Init&#34;,
-    ...       &#34;command&#34;: &#34;execute&#34;}]))  # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Example Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,
-             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},
-                       {&#39;id&#39;: {&#39;const&#39;: 42.42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Example Init&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Example Init&#39;,
-             &#39;command&#39;: &#39;execute&#39;}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-
-    Similar functionality could be reached by using the Log and Init plugins
-    to print messages and send some messages on the bus, but these would
-    clutter the test configuration and code to stop the indefinitely running
-    bus would have to be added to each and every test.
-
-    Incorrect plugin configurations can also be tested by this:
-    &gt;&gt;&gt; asyncio.run(test(
-    ...     {&#34;Example Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;}}, []))
-    &#39;messages&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;messages&#39;: {&#39;items&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                     &#39;type&#39;: &#39;array&#39;}},
-         &#39;required&#39;: [&#39;messages&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Init&#39;}
-    Configuration for &#39;Example Init&#39; is not valid.
-    &#34;&#34;&#34;
-    message_bus = MessageBus()
-
-    async def log(message):
-        if (&#39;sender&#39; in message and message[&#39;sender&#39;] == &#39;&#39; and
-                &#39;event&#39; in message and message[&#39;event&#39;] == &#39;registered&#39; and
-                &#39;client&#39; in message and message[&#39;client&#39;] == &#39;test()&#39;):
-            # Do not log own registration of &#39;test()&#39;:
-            return
-        print(f&#34;test(): {message}&#34;)
-    message_bus.register(&#39;test()&#39;, &#39;Test&#39;,
-                         [MessageTemplate()], [MessageTemplate()], log)
-
-    coroutines = _process_conf(message_bus, conf)
-    for coroutine in coroutines:
-        asyncio.create_task(coroutine)
-        # Give the created task opportunity to run:
-        await asyncio.sleep(0)
-    for message in messages:
-        await message_bus.send(Message(&#39;test()&#39;, message))
-        # Give immediate reactions to messages opportunity to happen:
-        await asyncio.sleep(0)
-    await asyncio.sleep(wait)
-    await message_bus._queue.join()</code></pre>
-</details>
-</section>
-<section>
-<h2 class="section-title" id="header-submodules">Sub-modules</h2>
-<dl>
-<dt><code class="name"><a title="controlpi.baseplugin" href="baseplugin.html">controlpi.baseplugin</a></code></dt>
-<dd>
-<div class="desc"><p>Define base class for all ControlPi plugins …</p></div>
-</dd>
-<dt><code class="name"><a title="controlpi.messagebus" href="messagebus.html">controlpi.messagebus</a></code></dt>
-<dd>
-<div class="desc"><p>Provide an asynchronous message bus …</p></div>
-</dd>
-<dt><code class="name"><a title="controlpi.pluginregistry" href="pluginregistry.html">controlpi.pluginregistry</a></code></dt>
-<dd>
-<div class="desc"><p>Provide a generic plugin system …</p></div>
-</dd>
-</dl>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-functions">Functions</h2>
-<dl>
-<dt id="controlpi.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>conf: Dict[str, Dict[str, Any]]) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run the ControlPi system based on a configuration.</p>
-<p>Setup message bus, process given configuration, and run message bus and
-plugins concurrently and indefinitely.</p>
-<p>This function is mainly used by <strong>main</strong>.py to run a ControlPi system
-based on a configuration loaded from a configuration JSON file on disk.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def test_coroutine():
-...     conf = {&quot;Example Init&quot;:
-...             {&quot;plugin&quot;: &quot;Init&quot;,
-...              &quot;messages&quot;: [{&quot;id&quot;: 42,
-...                            &quot;content&quot;: &quot;Test Message&quot;},
-...                           {&quot;id&quot;: 42.42,
-...                            &quot;content&quot;: &quot;Second Message&quot;}]},
-...             &quot;Example Log&quot;:
-...             {&quot;plugin&quot;: &quot;Log&quot;,
-...              &quot;filter&quot;: [{&quot;sender&quot;: {&quot;const&quot;: &quot;Example Init&quot;}}]}}
-...     run_task = asyncio.create_task(run(conf))
-...     await asyncio.sleep(0.1)
-...     run_task.cancel()
-&gt;&gt;&gt; asyncio.run(test_coroutine())  # doctest: +NORMALIZE_WHITESPACE
-Example Log: {'sender': 'Example Init',
-              'id': 42, 'content': 'Test Message'}
-Example Log: {'sender': 'Example Init',
-              'id': 42.42, 'content': 'Second Message'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(conf: Dict[str, PluginConf]) -&gt; None:
-    &#34;&#34;&#34;Run the ControlPi system based on a configuration.
-
-    Setup message bus, process given configuration, and run message bus and
-    plugins concurrently and indefinitely.
-
-    This function is mainly used by __main__.py to run a ControlPi system
-    based on a configuration loaded from a configuration JSON file on disk.
-
-    &gt;&gt;&gt; async def test_coroutine():
-    ...     conf = {&#34;Example Init&#34;:
-    ...             {&#34;plugin&#34;: &#34;Init&#34;,
-    ...              &#34;messages&#34;: [{&#34;id&#34;: 42,
-    ...                            &#34;content&#34;: &#34;Test Message&#34;},
-    ...                           {&#34;id&#34;: 42.42,
-    ...                            &#34;content&#34;: &#34;Second Message&#34;}]},
-    ...             &#34;Example Log&#34;:
-    ...             {&#34;plugin&#34;: &#34;Log&#34;,
-    ...              &#34;filter&#34;: [{&#34;sender&#34;: {&#34;const&#34;: &#34;Example Init&#34;}}]}}
-    ...     run_task = asyncio.create_task(run(conf))
-    ...     await asyncio.sleep(0.1)
-    ...     run_task.cancel()
-    &gt;&gt;&gt; asyncio.run(test_coroutine())  # doctest: +NORMALIZE_WHITESPACE
-    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,
-                  &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    Example Log: {&#39;sender&#39;: &#39;Example Init&#39;,
-                  &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-    &#34;&#34;&#34;
-    message_bus = MessageBus()
-    coroutines = _process_conf(message_bus, conf)
-    try:
-        await asyncio.gather(*coroutines)
-    except asyncio.exceptions.CancelledError:
-        pass</code></pre>
-</details>
-</dd>
-<dt id="controlpi.test"><code class="name flex">
-<span>async def <span class="ident">test</span></span>(<span>conf: Dict[str, Dict[str, Any]], messages: List[Dict[str, Any]], wait: float = 0.0) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Test configuration of ControlPi system.</p>
-<p>Setup message bus, process given configuration, run message bus and
-plugins concurrently, send given messages on message bus and print all
-messages on message bus. Terminate when queue of message bus is empty.</p>
-<p>This function allows to test single plugins or small plugin
-configurations with minimal boilerplate code:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(test(
-...     {&quot;Example Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,
-...                       &quot;messages&quot;: [{&quot;id&quot;: 42,
-...                                     &quot;content&quot;: &quot;Test Message&quot;},
-...                                    {&quot;id&quot;: 42.42,
-...                                     &quot;content&quot;: &quot;Second Message&quot;}]}},
-...     [{&quot;target&quot;: &quot;Example Init&quot;,
-...       &quot;command&quot;: &quot;execute&quot;}]))  # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Example Init', 'plugin': 'Init',
-         'sends': [{'id': {'const': 42},
-                    'content': {'const': 'Test Message'}},
-                   {'id': {'const': 42.42},
-                    'content': {'const': 'Second Message'}}],
-         'receives': [{'target': {'const': 'Example Init'},
-                       'command': {'const': 'execute'}}]}
-test(): {'sender': 'Example Init',
-         'id': 42, 'content': 'Test Message'}
-test(): {'sender': 'Example Init',
-         'id': 42.42, 'content': 'Second Message'}
-test(): {'sender': 'test()', 'target': 'Example Init',
-         'command': 'execute'}
-test(): {'sender': 'Example Init',
-         'id': 42, 'content': 'Test Message'}
-test(): {'sender': 'Example Init',
-         'id': 42.42, 'content': 'Second Message'}
-</code></pre>
-<p>Similar functionality could be reached by using the Log and Init plugins
-to print messages and send some messages on the bus, but these would
-clutter the test configuration and code to stop the indefinitely running
-bus would have to be added to each and every test.</p>
-<p>Incorrect plugin configurations can also be tested by this:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(test(
-...     {&quot;Example Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;}}, []))
-'messages' is a required property
-&lt;BLANKLINE&gt;
-Failed validating 'required' in schema:
-    {'properties': {'messages': {'items': {'type': 'object'},
-                                 'type': 'array'}},
-     'required': ['messages']}
-&lt;BLANKLINE&gt;
-On instance:
-    {'plugin': 'Init'}
-Configuration for 'Example Init' is not valid.
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def test(conf: Dict[str, PluginConf],
-               messages: List[Dict[str, Any]],
-               wait: float = 0.0) -&gt; None:
-    &#34;&#34;&#34;Test configuration of ControlPi system.
-
-    Setup message bus, process given configuration, run message bus and
-    plugins concurrently, send given messages on message bus and print all
-    messages on message bus. Terminate when queue of message bus is empty.
-
-    This function allows to test single plugins or small plugin
-    configurations with minimal boilerplate code:
-    &gt;&gt;&gt; asyncio.run(test(
-    ...     {&#34;Example Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-    ...                       &#34;messages&#34;: [{&#34;id&#34;: 42,
-    ...                                     &#34;content&#34;: &#34;Test Message&#34;},
-    ...                                    {&#34;id&#34;: 42.42,
-    ...                                     &#34;content&#34;: &#34;Second Message&#34;}]}},
-    ...     [{&#34;target&#34;: &#34;Example Init&#34;,
-    ...       &#34;command&#34;: &#34;execute&#34;}]))  # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Example Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,
-             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},
-                       {&#39;id&#39;: {&#39;const&#39;: 42.42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Example Init&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Example Init&#39;,
-             &#39;command&#39;: &#39;execute&#39;}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Example Init&#39;,
-             &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-
-    Similar functionality could be reached by using the Log and Init plugins
-    to print messages and send some messages on the bus, but these would
-    clutter the test configuration and code to stop the indefinitely running
-    bus would have to be added to each and every test.
-
-    Incorrect plugin configurations can also be tested by this:
-    &gt;&gt;&gt; asyncio.run(test(
-    ...     {&#34;Example Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;}}, []))
-    &#39;messages&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;messages&#39;: {&#39;items&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                     &#39;type&#39;: &#39;array&#39;}},
-         &#39;required&#39;: [&#39;messages&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Init&#39;}
-    Configuration for &#39;Example Init&#39; is not valid.
-    &#34;&#34;&#34;
-    message_bus = MessageBus()
-
-    async def log(message):
-        if (&#39;sender&#39; in message and message[&#39;sender&#39;] == &#39;&#39; and
-                &#39;event&#39; in message and message[&#39;event&#39;] == &#39;registered&#39; and
-                &#39;client&#39; in message and message[&#39;client&#39;] == &#39;test()&#39;):
-            # Do not log own registration of &#39;test()&#39;:
-            return
-        print(f&#34;test(): {message}&#34;)
-    message_bus.register(&#39;test()&#39;, &#39;Test&#39;,
-                         [MessageTemplate()], [MessageTemplate()], log)
-
-    coroutines = _process_conf(message_bus, conf)
-    for coroutine in coroutines:
-        asyncio.create_task(coroutine)
-        # Give the created task opportunity to run:
-        await asyncio.sleep(0)
-    for message in messages:
-        await message_bus.send(Message(&#39;test()&#39;, message))
-        # Give immediate reactions to messages opportunity to happen:
-        await asyncio.sleep(0)
-    await asyncio.sleep(wait)
-    await message_bus._queue.join()</code></pre>
-</details>
-</dd>
-</dl>
-</section>
-<section>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3><a href="#header-submodules">Sub-modules</a></h3>
-<ul>
-<li><code><a title="controlpi.baseplugin" href="baseplugin.html">controlpi.baseplugin</a></code></li>
-<li><code><a title="controlpi.messagebus" href="messagebus.html">controlpi.messagebus</a></code></li>
-<li><code><a title="controlpi.pluginregistry" href="pluginregistry.html">controlpi.pluginregistry</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-functions">Functions</a></h3>
-<ul class="">
-<li><code><a title="controlpi.run" href="#controlpi.run">run</a></code></li>
-<li><code><a title="controlpi.test" href="#controlpi.test">test</a></code></li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi/messagebus.html b/doc/controlpi/messagebus.html
deleted file mode 100644 (file)
index 46bea91..0000000
+++ /dev/null
@@ -1,4244 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi.messagebus API documentation</title>
-<meta name="description" content="Provide an asynchronous message bus …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Module <code>controlpi.messagebus</code></h1>
-</header>
-<section id="section-intro">
-<p>Provide an asynchronous message bus.</p>
-<p>A message is a dictionary with string keys and string, integer, float,
-Boolean, dictionary, or list values, where the inner dictionaries again
-have string keys and these values and the inner lists also have elements of
-these types. All messages have a special key 'sender' with the name of the
-sending client as string value, which is set by the constructor:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender', {'key 1': 'value 1'})
-&gt;&gt;&gt; m['key 2'] = 'value 2'
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender', 'key 1': 'value 1', 'key 2': 'value 2'}
-</code></pre>
-<p>A message template is a mapping from string keys to JSON schemas as values.
-A message template matches a message if all keys of the template are
-contained in the message and the values in the message validate against the
-respective schemas. An empty mapping therefore matches all messages.</p>
-<p>The bus executes asynchronous callbacks for all messages to be received by
-a client. We use a simple callback printing the message in all examples:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; def callback_for_receiver(receiver):
-...     async def callback(message):
-...         print(f&quot;{receiver}: {message}&quot;)
-...     return callback
-</code></pre>
-<p>Clients can be registered at the bus with a name, lists of message templates
-they want to use for sending and receiving and a callback function for
-receiving. An empty list of templates means that the client does not want to
-send or receive any messages, respectively. A list with an empty template
-means that it wants to send arbitrary or receive all messages, respectively:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def setup(bus):
-...     bus.register('Logger', 'Test Plugin',
-...                  [],
-...                  [{}],
-...                  callback_for_receiver('Logger'))
-...     bus.register('Client 1', 'Test Plugin',
-...                  [{'k1': {'type': 'string'}}],
-...                  [{'target': {'const': 'Client 1'}}],
-...                  callback_for_receiver('Client 1'))
-</code></pre>
-<p>While most clients should always use their own name for sending, this is not
-enforced and debugging or management clients could send messages on behalf
-of arbitrary client names.</p>
-<p>The name of a client has to be unique and is not allowed to be empty
-(otherwise registration fails).</p>
-<p>The empty name is used to refer to the bus itself. The bus sends messages
-for registrations and deregistrations of clients containing their complete
-interface of send and receive templates. This can be used to allow dynamic
-(debug) clients to deal with arbitrary configurations of clients. The bus
-also reacts to 'get clients' command messages by sending the complete
-information of all currently registered clients.</p>
-<p>Clients can send to the bus with the send function. Each message has to
-declare a sender. The send templates of that sender are checked for a
-template matching the message:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def send(bus):
-...     print(&quot;Sending messages.&quot;)
-...     await bus.send({'sender': 'Client 1', 'k1': 'Test'})
-...     await bus.send({'sender': '', 'target': 'Client 1'})
-</code></pre>
-<p>The run function executes the message bus forever. If we want to stop it, we
-have to explicitly cancel the task:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     await setup(bus)
-...     bus_task = asyncio.create_task(bus.run())
-...     await send(bus)
-...     await asyncio.sleep(0)
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-Sending messages.
-Logger: {'sender': '', 'event': 'registered',
-         'client': 'Logger', 'plugin': 'Test Plugin',
-         'sends': [], 'receives': [{}]}
-Logger: {'sender': '', 'event': 'registered',
-         'client': 'Client 1', 'plugin': 'Test Plugin',
-         'sends': [{'k1': {'type': 'string'}}],
-         'receives': [{'target': {'const': 'Client 1'}}]}
-Logger: {'sender': 'Client 1', 'k1': 'Test'}
-Logger: {'sender': '', 'target': 'Client 1'}
-Client 1: {'sender': '', 'target': 'Client 1'}
-</code></pre>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Provide an asynchronous message bus.
-
-A message is a dictionary with string keys and string, integer, float,
-Boolean, dictionary, or list values, where the inner dictionaries again
-have string keys and these values and the inner lists also have elements of
-these types. All messages have a special key &#39;sender&#39; with the name of the
-sending client as string value, which is set by the constructor:
-&gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})
-&gt;&gt;&gt; m[&#39;key 2&#39;] = &#39;value 2&#39;
-&gt;&gt;&gt; print(m)
-{&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-
-A message template is a mapping from string keys to JSON schemas as values.
-A message template matches a message if all keys of the template are
-contained in the message and the values in the message validate against the
-respective schemas. An empty mapping therefore matches all messages.
-
-The bus executes asynchronous callbacks for all messages to be received by
-a client. We use a simple callback printing the message in all examples:
-&gt;&gt;&gt; def callback_for_receiver(receiver):
-...     async def callback(message):
-...         print(f&#34;{receiver}: {message}&#34;)
-...     return callback
-
-Clients can be registered at the bus with a name, lists of message templates
-they want to use for sending and receiving and a callback function for
-receiving. An empty list of templates means that the client does not want to
-send or receive any messages, respectively. A list with an empty template
-means that it wants to send arbitrary or receive all messages, respectively:
-&gt;&gt;&gt; async def setup(bus):
-...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,
-...                  [],
-...                  [{}],
-...                  callback_for_receiver(&#39;Logger&#39;))
-...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-...                  callback_for_receiver(&#39;Client 1&#39;))
-
-While most clients should always use their own name for sending, this is not
-enforced and debugging or management clients could send messages on behalf
-of arbitrary client names.
-
-The name of a client has to be unique and is not allowed to be empty
-(otherwise registration fails).
-
-The empty name is used to refer to the bus itself. The bus sends messages
-for registrations and deregistrations of clients containing their complete
-interface of send and receive templates. This can be used to allow dynamic
-(debug) clients to deal with arbitrary configurations of clients. The bus
-also reacts to &#39;get clients&#39; command messages by sending the complete
-information of all currently registered clients.
-
-Clients can send to the bus with the send function. Each message has to
-declare a sender. The send templates of that sender are checked for a
-template matching the message:
-&gt;&gt;&gt; async def send(bus):
-...     print(&#34;Sending messages.&#34;)
-...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;})
-...     await bus.send({&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;})
-
-The run function executes the message bus forever. If we want to stop it, we
-have to explicitly cancel the task:
-&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     await setup(bus)
-...     bus_task = asyncio.create_task(bus.run())
-...     await send(bus)
-...     await asyncio.sleep(0)
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-Sending messages.
-Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-         &#39;sends&#39;: [], &#39;receives&#39;: [{}]}
-Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-         &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}
-Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}
-Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-Client 1: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-&#34;&#34;&#34;
-import asyncio
-import json
-import jsonschema  # type: ignore
-
-from typing import Union, Dict, List, Any, Iterable, Callable, Coroutine
-MessageValue = Union[None, str, int, float, bool, Dict[str, Any], List[Any]]
-# Should really be:
-# MessageValue = Union[None, str, int, float, bool,
-#                      Dict[str, &#39;MessageValue&#39;], List[&#39;MessageValue&#39;]]
-# But mypy does not support recursion by now:
-# https://github.com/python/mypy/issues/731
-JSONSchema = Union[bool, Dict[str, MessageValue]]
-# Could be even more specific.
-MessageCallback = Callable[[&#39;Message&#39;], Coroutine[Any, Any, None]]
-
-
-class Message(Dict[str, MessageValue]):
-    &#34;&#34;&#34;Define arbitrary message.
-
-    Messages are dictionaries with string keys and values that are strings,
-    integers, floats, Booleans, dictionaries that recursively have string
-    keys and values of any of these types, or lists with elements that have
-    any of these types. These constraints are checked when setting key-value
-    pairs of the message.
-
-    A message has to have a sender, which is set by the constructor:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;}
-
-    A dictionary can be given to the constructor:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-
-    Or the message can be modified after construction:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})
-    &gt;&gt;&gt; m[&#39;key 2&#39;] = &#39;value 2&#39;
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-    &#34;&#34;&#34;
-
-    def __init__(self, sender: str,
-                 init: Dict[str, MessageValue] = None) -&gt; None:
-        &#34;&#34;&#34;Initialise message.
-
-        Message is initialised with given sender and possibly given
-        key-value pairs:
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;}
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}
-
-        The sender can be overwritten by the key-value pairs:
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;sender&#39;: &#39;Another sender&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Another sender&#39;}
-        &#34;&#34;&#34;
-        if not isinstance(sender, str):
-            raise TypeError(f&#34;&#39;{sender}&#39; is not a valid sender name&#34;
-                            &#34; (not a string).&#34;)
-        self[&#39;sender&#39;] = sender
-        if init is not None:
-            self.update(init)
-
-    @staticmethod
-    def check_value(value: MessageValue) -&gt; bool:
-        &#34;&#34;&#34;Check recursively if a given value is valid.
-
-        None, strings, integers, floats and Booleans are valid:
-        &gt;&gt;&gt; Message.check_value(None)
-        True
-        &gt;&gt;&gt; Message.check_value(&#39;Spam&#39;)
-        True
-        &gt;&gt;&gt; Message.check_value(42)
-        True
-        &gt;&gt;&gt; Message.check_value(42.42)
-        True
-        &gt;&gt;&gt; Message.check_value(False)
-        True
-
-        Other basic types are not valid:
-        &gt;&gt;&gt; Message.check_value(b&#39;bytes&#39;)
-        False
-        &gt;&gt;&gt; Message.check_value(1j)
-        False
-
-        Dictionaries with string keys and recursively valid values are valid:
-        &gt;&gt;&gt; Message.check_value({&#39;str value&#39;: &#39;Spam&#39;, &#39;int value&#39;: 42,
-        ...                      &#39;float value&#39;: 42.42, &#39;bool value&#39;: False})
-        True
-
-        Empty dictionaries are valid:
-        &gt;&gt;&gt; Message.check_value({})
-        True
-
-        Dictionaries with other keys are not valid:
-        &gt;&gt;&gt; Message.check_value({42: &#39;int key&#39;})
-        False
-
-        Dictionaries with invalid values are not valid:
-        &gt;&gt;&gt; Message.check_value({&#39;complex value&#39;: 1j})
-        False
-
-        Lists with valid elements are valid:
-        &gt;&gt;&gt; Message.check_value([&#39;Spam&#39;, 42, 42.42, False])
-        True
-
-        Empty lists are valid:
-        &gt;&gt;&gt; Message.check_value([])
-        True
-
-        Lists with invalid elements are not valid:
-        &gt;&gt;&gt; Message.check_value([1j])
-        False
-        &#34;&#34;&#34;
-        if value is None:
-            return True
-        elif (isinstance(value, str) or isinstance(value, int) or
-                isinstance(value, float) or isinstance(value, bool)):
-            return True
-        elif isinstance(value, dict):
-            for key in value:
-                if not isinstance(key, str):
-                    return False
-                if not Message.check_value(value[key]):
-                    return False
-            return True
-        elif isinstance(value, list):
-            for element in value:
-                if not Message.check_value(element):
-                    return False
-            return True
-        return False
-
-    def __setitem__(self, key: str, value: MessageValue) -&gt; None:
-        &#34;&#34;&#34;Check key and value before putting pair into dict.
-
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m[&#39;key&#39;] = &#39;value&#39;
-        &gt;&gt;&gt; m[&#39;dict&#39;] = {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}
-        &gt;&gt;&gt; print(m)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;,
-         &#39;dict&#39;: {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}}
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m[42] = &#39;int key&#39;
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m[&#39;complex value&#39;] = 1j
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-        &#34;&#34;&#34;
-        if not isinstance(key, str):
-            raise TypeError(f&#34;&#39;{key}&#39; is not a valid key in Message&#34;
-                            &#34; (not a string).&#34;)
-        if not self.check_value(value):
-            raise TypeError(f&#34;&#39;{value}&#39; is not a valid value in Message.&#34;)
-        super().__setitem__(key, value)
-
-    def update(self, *args, **kwargs) -&gt; None:
-        &#34;&#34;&#34;Override update to use validity checks.
-
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m.update({&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-        &gt;&gt;&gt; m.update({42: &#39;int key&#39;})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m.update({&#39;complex value&#39;: 1j})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-
-        This is also used in __init__:
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {42: &#39;int key&#39;})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;complex value&#39;: 1j})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-        &#34;&#34;&#34;
-        if args:
-            if len(args) &gt; 1:
-                raise TypeError(&#34;update expected at most 1 argument,&#34;
-                                f&#34; got {len(args)}&#34;)
-            other = dict(args[0])
-            for key in other:
-                self[key] = other[key]
-        for key in kwargs:
-            self[key] = kwargs[key]
-
-    def setdefault(self, key: str, value: MessageValue = None) -&gt; MessageValue:
-        &#34;&#34;&#34;Override setdefault to use validity checks.
-
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 1&#39;)
-        &#39;value 1&#39;
-        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 2&#39;)
-        &#39;value 1&#39;
-        &gt;&gt;&gt; m.setdefault(42, &#39;int key&#39;)
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m.setdefault(&#39;complex value&#39;, 1j)
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-
-        But __setitem__ is not called if the key is already present:
-        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, 1j)
-        &#39;value 1&#39;
-        &#34;&#34;&#34;
-        if key not in self:
-            self[key] = value
-        return self[key]
-
-
-class MessageTemplate(Dict[str, JSONSchema]):
-    &#34;&#34;&#34;Define a message template.
-
-    A message template is a mapping from string keys to JSON schemas as
-    values:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-    ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;}})
-    &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,
-    ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-    ...                              &#39;key 2&#39;: True}}
-
-    A message template matches a message if all keys of the template are
-    contained in the message and the values in the message validate against
-    the respective schemas:
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-    ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42, &#39;key 2&#39;: None}}))
-    True
-
-    An empty mapping therefore matches all messages:
-    &gt;&gt;&gt; t = MessageTemplate()
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;arbitrary&#39;: &#39;content&#39;}))
-    True
-    &#34;&#34;&#34;
-
-    def __init__(self, init: Dict[str, JSONSchema] = None) -&gt; None:
-        &#34;&#34;&#34;Initialise message.
-
-        Template is initialised empty or with given key-value pairs:
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; print(t)
-        {}
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})
-        &gt;&gt;&gt; print(t)
-        {&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}
-        &#34;&#34;&#34;
-        if init is not None:
-            self.update(init)
-
-    @staticmethod
-    def from_message(message: Message) -&gt; &#39;MessageTemplate&#39;:
-        &#34;&#34;&#34;Create template from message.
-
-        Template witch constant schemas is created from message:
-        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;})
-        &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-        &gt;&gt;&gt; print(t)
-        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}
-        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},
-        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})
-        &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},
-         &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,
-                  &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},
-                                 &#39;float&#39;: {&#39;const&#39;: 42.42}}},
-         &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,
-                  &#39;items&#39;: [{&#39;const&#39;: None},
-                            {&#39;const&#39;: True},
-                            {&#39;const&#39;: &#39;string&#39;}]}}
-
-        This is especially useful for clients that send certain fully
-        predefined messages, where the message is given in the configuration
-        and the template for the registration can be constructed by this
-        method.
-        &#34;&#34;&#34;
-        def schema_from_value(value: MessageValue) -&gt; JSONSchema:
-            schema: JSONSchema = False
-            if value is None:
-                schema = {&#39;const&#39;: None}
-            elif (isinstance(value, str) or isinstance(value, int) or
-                    isinstance(value, float) or isinstance(value, bool)):
-                schema = {&#39;const&#39;: value}
-            elif isinstance(value, dict):
-                properties = {}
-                for inner_key in value:
-                    inner_value: Message = value[inner_key]
-                    properties[inner_key] = schema_from_value(inner_value)
-                schema = {&#39;type&#39;: &#39;object&#39;,
-                          &#39;properties&#39;: properties}
-            elif isinstance(value, list):
-                schema = {&#39;type&#39;: &#39;array&#39;,
-                          &#39;items&#39;: [schema_from_value(element)
-                                    for element in value]}
-            return schema
-        template = MessageTemplate()
-        for key in message:
-            template[key] = schema_from_value(message[key])
-        return template
-
-    def __setitem__(self, key: str, value: JSONSchema) -&gt; None:
-        &#34;&#34;&#34;Check key and value before putting pair into dict.
-
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; t[&#39;key 1&#39;] = {&#39;const&#39;: &#39;value&#39;}
-        &gt;&gt;&gt; t[&#39;key 2&#39;] = {&#39;type&#39;: &#39;string&#39;}
-        &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,
-        ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                              &#39;key 2&#39;: True}}
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}}
-        &gt;&gt;&gt; t[42] = {&#39;const&#39;: &#39;int key&#39;}
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t[&#39;key&#39;] = &#39;schema&#39;  # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-        &#34;&#34;&#34;
-        if not isinstance(key, str):
-            raise TypeError(f&#34;&#39;{key}&#39; is not a valid key in MessageTemplate&#34;
-                            &#34; (not a string).&#34;)
-        try:
-            jsonschema.Draft7Validator.check_schema(value)
-            # Draft7Validator is hardcoded, because _LATEST_VERSION is
-            # non-public in jsonschema and we also perhaps do not want to
-            # upgrade automatically.
-        except jsonschema.exceptions.SchemaError:
-            raise TypeError(f&#34;&#39;{value}&#39; is not a valid value in&#34;
-                            &#34; MessageTemplate (not a valid JSON schema).&#34;)
-        super().__setitem__(key, value)
-
-    def update(self, *args, **kwargs) -&gt; None:
-        &#34;&#34;&#34;Override update to use validity checks.
-
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; t.update({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-        ...           &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-        ...           &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-        ...                     &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                    &#39;key 2&#39;: True}}})
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}}
-        &gt;&gt;&gt; t.update({42: {&#39;const&#39;: &#39;int key&#39;}})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t.update({&#39;key&#39;: &#39;schema&#39;})  # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-
-        This is also used in __init__:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-        ...                                &#39;properties&#39;: {
-        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                    &#39;key 2&#39;: True}}})
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}}
-        &gt;&gt;&gt; t = MessageTemplate({42: {&#39;const&#39;: &#39;int key&#39;}})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: &#39;schema&#39;})
-        ... # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-        &#34;&#34;&#34;
-        if args:
-            if len(args) &gt; 1:
-                raise TypeError(&#34;update expected at most 1 argument,&#34;
-                                f&#34; got {len(args)}&#34;)
-            other = dict(args[0])
-            for key in other:
-                self[key] = other[key]
-        for key in kwargs:
-            self[key] = kwargs[key]
-
-    def setdefault(self, key: str, value: JSONSchema = None) -&gt; JSONSchema:
-        &#34;&#34;&#34;Override setdefault to use validity checks.
-
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, {&#39;const&#39;: &#39;value&#39;})
-        {&#39;const&#39;: &#39;value&#39;}
-        &gt;&gt;&gt; t.setdefault(&#39;key 2&#39;, {&#39;type&#39;: &#39;string&#39;})
-        {&#39;type&#39;: &#39;string&#39;}
-        &gt;&gt;&gt; t.setdefault(&#39;key 3&#39;, {&#39;type&#39;: &#39;object&#39;,
-        ...                        &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                       &#39;key 2&#39;: True}})
-        ... # doctest: +NORMALIZE_WHITESPACE
-        {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}
-        &gt;&gt;&gt; t.setdefault(42, {&#39;const&#39;: &#39;int key&#39;})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t.setdefault(&#39;key&#39;, &#39;schema&#39;)  # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-
-        But __setitem__ is not called if the key is already present:
-        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, &#39;schema&#39;)
-        {&#39;const&#39;: &#39;value&#39;}
-        &#34;&#34;&#34;
-        if key not in self:
-            if value is not None:
-                self[key] = value
-            else:
-                self[key] = True
-        return self[key]
-
-    def check(self, message: Message) -&gt; bool:
-        &#34;&#34;&#34;Check message against this template.
-
-        Constant values have to match exactly:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;other value&#39;}))
-        False
-
-        But for integers, floats with the same value are also valid:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: 42}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))
-        True
-
-        Type integer is valid for floats with zero fractional part, but
-        not by floats with non-zero fractional part:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;integer&#39;}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))
-        False
-
-        Type number is valid for arbitrary ints or floats:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;number&#39;}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))
-        True
-
-        All keys in template have to be present in message:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-        ...                                &#39;properties&#39;: {
-        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                    &#39;key 2&#39;: True,
-        ...                                    &#39;key 3&#39;: False}}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;}))
-        False
-
-        But for nested objects their properties do not necessarily have
-        to be present:
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-        ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42}}))
-        True
-
-        Schema True matches everything (even None):
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-        ...                  &#39;key 3&#39;: {&#39;key 2&#39;: None}}))
-        True
-
-        Schema False matches nothing:
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-        ...                  &#39;key 3&#39;: {&#39;key 3&#39;: True}}))
-        False
-
-        Message is valid for the constant template created from it:
-        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},
-        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})
-        &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-        &gt;&gt;&gt; t.check(m)
-        True
-        &#34;&#34;&#34;
-        for key in self:
-            if key not in message:
-                return False
-            else:
-                validator = jsonschema.Draft7Validator(self[key])
-                for error in validator.iter_errors(message[key]):
-                    return False
-        return True
-
-
-class MessageTemplateRegistry:
-    &#34;&#34;&#34;Manage a collection of message templates with registered clients.
-
-    A new MessageTemplateRegistry is created by:
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-
-    Client names (strings) can be registered for message templates, which
-    are mappings from keys to JSON schemas:
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-
-    The check function checks if the templates registered for a client
-    match a given message:
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 1&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-
-    Clients can be registered for values validating against arbitrary JSON
-    schemas, e.g. all values of a certain type:
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 2&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 3&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 3&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True
-
-    The order of key-value pairs does not have to match the order in the
-    messages and keys can be left out:
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;C 4&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 4&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True
-
-    A registration for an empty template matches all messages:
-    &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 5&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True
-
-    A client can be registered for multiple templates:
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 6&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-
-    Clients can be deregistered again (the result is False if the registry
-    is empty after the deletion):
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 7&#39;)
-    &gt;&gt;&gt; r.delete(&#39;C 7&#39;)
-    True
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 7&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-
-    The get function returns all clients with registered templates matching
-    a given message:
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.get(m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;]
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;, &#39;C 4&#39;]
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 2&#39;, &#39;C 6&#39;]
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 3&#39;, &#39;C 4&#39;]
-
-    The get_templates function returns all templates for a given client:
-    &gt;&gt;&gt; for c in [&#39;C 1&#39;, &#39;C 2&#39;, &#39;C 3&#39;, &#39;C 4&#39;, &#39;C 5&#39;, &#39;C 6&#39;]:
-    ...     print(f&#34;{c}: {r.get_templates(c)}&#34;)
-    C 1: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-    C 2: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]
-    C 3: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]
-    C 4: [{&#39;k2&#39;: {&#39;const&#39;: 2}}]
-    C 5: [{}]
-    C 6: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-    &#34;&#34;&#34;
-
-    def __init__(self) -&gt; None:
-        &#34;&#34;&#34;Initialise an empty registry.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &#34;&#34;&#34;
-        self._clients: List[str] = []
-        self._children: Dict[str, Dict[str, MessageTemplateRegistry]] = {}
-
-    def insert(self, template: MessageTemplate, client: str) -&gt; None:
-        &#34;&#34;&#34;Register a client for a template.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 2&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)
-        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-
-        Implementation details:
-        -----------------------
-        The tree nodes on the way to a registered object are used/created
-        in the order given in the message template, which can be used to
-        design more efficient lookups (e.g., putting rarer key-value pairs
-        earlier in the template).
-        &gt;&gt;&gt; r._clients
-        [&#39;C 5&#39;]
-        &gt;&gt;&gt; r._children.keys()
-        dict_keys([&#39;k1&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._clients
-        []
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children.keys()
-        dict_keys([&#39;k2&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children[&#39;k2&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-        [&#39;C 1&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-        [&#39;C 2&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._clients
-        []
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._children.keys()
-        dict_keys([&#39;k2&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._children[&#39;k2&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-        [&#39;C 3&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-        [&#39;C 4&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &#34;&#34;&#34;
-        if not template:
-            self._clients.append(client)
-        else:
-            key, schema = next(iter(template.items()))
-            schema_string = json.dumps(schema)
-            reduced_template = MessageTemplate({k: template[k]
-                                                for k in template
-                                                if k != key})
-            if key not in self._children:
-                self._children[key] = {}
-            if schema_string not in self._children[key]:
-                self._children[key][schema_string] = MessageTemplateRegistry()
-            self._children[key][schema_string].insert(reduced_template, client)
-
-    def delete(self, client: str) -&gt; bool:
-        &#34;&#34;&#34;Unregister a client from all templates.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 2&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)
-        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-        &gt;&gt;&gt; r.delete(&#39;C 3&#39;)
-        True
-        &gt;&gt;&gt; r.delete(&#39;C 4&#39;)
-        True
-
-        Implementation details:
-        -----------------------
-        If parts of the tree become superfluous by the deletion of the
-        client, they are also completely removed to reduce the lookup
-        effort and keep the tree clean.
-        &gt;&gt;&gt; r._clients
-        [&#39;C 5&#39;]
-        &gt;&gt;&gt; r._children.keys()
-        dict_keys([&#39;k1&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._clients
-        []
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children.keys()
-        dict_keys([&#39;k2&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children[&#39;k2&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-        [&#39;C 1&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-        [&#39;C 2&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &#34;&#34;&#34;
-        self._clients = [c for c in self._clients if c != client]
-        new_children: Dict[str, Dict[str, MessageTemplateRegistry]] = {}
-        for key in self._children:
-            new_children[key] = {}
-            for schema in self._children[key]:
-                if self._children[key][schema].delete(client):
-                    new_children[key][schema] = self._children[key][schema]
-            if not new_children[key]:
-                del new_children[key]
-        self._children = new_children
-        if self._clients or self._children:
-            return True
-        return False
-
-    def check(self, client: str, message: Message) -&gt; bool:
-        &#34;&#34;&#34;Get if a client has a registered template matching a message.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-        ...     print(f&#34;{m}: {r.check(&#39;Client 1&#39;, m)}&#34;)
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: False
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;Client 2&#39;)
-        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-        ...     print(f&#34;{m}: {r.check(&#39;Client 2&#39;, m)}&#34;)
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-        &#34;&#34;&#34;
-        if client in self._clients:
-            return True
-        for key in self._children:
-            if key in message:
-                for schema_string in self._children[key]:
-                    schema = json.loads(schema_string)
-                    validator = jsonschema.Draft7Validator(schema)
-                    validated = True
-                    for error in validator.iter_errors(message[key]):
-                        validated = False
-                    if validated:
-                        child = self._children[key][schema_string]
-                        if child.check(client, message):
-                            return True
-        return False
-
-    def get(self, message: Message) -&gt; List[str]:
-        &#34;&#34;&#34;Get all clients registered for templates matching a message.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;Client 2&#39;)
-        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-        ...     print(f&#34;{m}: {r.get(m)}&#34;)
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: [&#39;Client 1&#39;, &#39;Client 2&#39;]
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: [&#39;Client 2&#39;]
-        &#34;&#34;&#34;
-        result = []
-        for client in self._clients:
-            if client not in result:
-                result.append(client)
-        for key in self._children:
-            if key in message:
-                for schema_string in self._children[key]:
-                    schema = json.loads(schema_string)
-                    validator = jsonschema.Draft7Validator(schema)
-                    validated = True
-                    for error in validator.iter_errors(message[key]):
-                        validated = False
-                    if validated:
-                        child = self._children[key][schema_string]
-                        for client in child.get(message):
-                            if client not in result:
-                                result.append(client)
-        return result
-
-    def get_templates(self, client: str) -&gt; List[MessageTemplate]:
-        &#34;&#34;&#34;Get all templates for a client.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 1&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},
-        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;Client 2&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 2&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},
-        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 3&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 3&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;Client 4&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 4&#39;)
-        [{&#39;k2&#39;: {&#39;const&#39;: 2}}]
-        &gt;&gt;&gt; r.insert({}, &#39;Client 5&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 5&#39;)
-        [{}]
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 6&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-        &#34;&#34;&#34;
-        result = []
-        if client in self._clients:
-            result.append(MessageTemplate())
-        for key in self._children:
-            for schema_string in self._children[key]:
-                schema = json.loads(schema_string)
-                child = self._children[key][schema_string]
-                for template in child.get_templates(client):
-                    current = MessageTemplate({key: schema})
-                    current.update(template)
-                    result.append(current)
-        return result
-
-
-class BusException(Exception):
-    &#34;&#34;&#34;Raise for errors in using message bus.&#34;&#34;&#34;
-
-
-class MessageBus:
-    &#34;&#34;&#34;Provide an asynchronous message bus.
-
-    The bus executes asynchronous callbacks for all messages to be received
-    by a client. We use a simple callback printing the message in all
-    examples:
-    &gt;&gt;&gt; def callback_for_receiver(receiver):
-    ...     print(f&#34;Creating callback for {receiver}.&#34;)
-    ...     async def callback(message):
-    ...         print(f&#34;{receiver}: {message}&#34;)
-    ...     return callback
-
-    Clients can be registered at the bus with a name, lists of message
-    templates they want to use for sending and receiving and a callback
-    function for receiving. An empty list of templates means that the
-    client does not want to send or receive any messages, respectively.
-    A list with an empty template means that it wants to send arbitrary
-    or receive all messages, respectively:
-    &gt;&gt;&gt; async def setup(bus):
-    ...     print(&#34;Setting up.&#34;)
-    ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,
-    ...                  [],
-    ...                  [{}],
-    ...                  callback_for_receiver(&#39;Logger&#39;))
-    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-    ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-    ...                  callback_for_receiver(&#39;Client 1&#39;))
-    ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-    ...                  [{}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-    ...                  callback_for_receiver(&#39;Client 2&#39;))
-
-    The bus itself is addressed by the empty string. It sends messages for
-    each registration and deregestration of a client with a key &#39;event&#39; and
-    a value of &#39;registered&#39; or &#39;unregistered&#39;, a key &#39;client&#39; with the
-    client&#39;s name as value and for registrations also keys &#39;sends&#39; and
-    &#39;receives&#39; with all templates registered for the client for sending and
-    receiving.
-
-    Clients can send to the bus with the send function. Each message has to
-    declare a sender. The send templates of that sender are checked for a
-    template matching the message. We cannot prevent arbitrary code from
-    impersonating any sender, but this should only be done in debugging or
-    management situations.
-
-    Messages that are intended for a specific client by convention have a
-    key &#39;target&#39; with the target client&#39;s name as value. Such messages are
-    often commands to the client to do something, which is by convention
-    indicated by a key &#39;command&#39; with a value that indicates what should be
-    done.
-
-    The bus, for example, reacts to a message with &#39;target&#39;: &#39;&#39; and
-    &#39;command&#39;: &#39;get clients&#39; by sending one message for each currently
-    registered with complete information about its registered send and
-    receive templates.
-
-    &gt;&gt;&gt; async def send(bus):
-    ...     print(&#34;Sending messages.&#34;)
-    ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;})
-    ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})
-    ...     await bus.send({&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;,
-    ...                     &#39;command&#39;: &#39;get clients&#39;})
-
-    The run function executes the message bus forever. If we want to stop
-    it, we have to explicitly cancel the task:
-    &gt;&gt;&gt; async def main():
-    ...     bus = MessageBus()
-    ...     await setup(bus)
-    ...     bus_task = asyncio.create_task(bus.run())
-    ...     await send(bus)
-    ...     await asyncio.sleep(0)
-    ...     bus_task.cancel()
-    &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-    Setting up.
-    Creating callback for Logger.
-    Creating callback for Client 1.
-    Creating callback for Client 2.
-    Sending messages.
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}
-    Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}
-    Logger: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-    Client 1: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;, &#39;command&#39;: &#39;get clients&#39;}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}
-    &#34;&#34;&#34;
-
-    def __init__(self) -&gt; None:
-        &#34;&#34;&#34;Initialise a new bus without clients.
-
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        self._queue: asyncio.Queue = asyncio.Queue()
-        self._plugins: Dict[str, str] = {}
-        self._send_reg: MessageTemplateRegistry = MessageTemplateRegistry()
-        self._recv_reg: MessageTemplateRegistry = MessageTemplateRegistry()
-        self._callbacks: Dict[str, MessageCallback] = {}
-
-    def register(self, client: str, plugin: str,
-                 sends: Iterable[MessageTemplate],
-                 receives: Iterable[MessageTemplate],
-                 callback: MessageCallback) -&gt; None:
-        &#34;&#34;&#34;Register a client at the message bus.
-
-        &gt;&gt;&gt; async def callback(message):
-        ...     print(message)
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,
-        ...                  [],    # send nothing
-        ...                  [{}],  # receive everything
-        ...                  callback)
-        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-        ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-        ...                      # send with key &#39;k1&#39; and string value
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-        ...                      # receive for this client
-        ...                  callback)
-        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-        ...                  [{}],  # send arbitrary
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-        ...                      # receive for this client
-        ...                  callback)
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        if not client:
-            raise BusException(&#34;Client name is not allowed to be empty.&#34;)
-        if client in self._plugins:
-            raise BusException(f&#34;Client &#39;{client}&#39; already registered&#34;
-                               &#34; at message bus.&#34;)
-        event = Message(&#39;&#39;)
-        event[&#39;event&#39;] = &#39;registered&#39;
-        event[&#39;client&#39;] = client
-        self._plugins[client] = plugin
-        event[&#39;plugin&#39;] = plugin
-        for template in sends:
-            self._send_reg.insert(template, client)
-        event[&#39;sends&#39;] = self._send_reg.get_templates(client)
-        for template in receives:
-            self._recv_reg.insert(template, client)
-        event[&#39;receives&#39;] = self._recv_reg.get_templates(client)
-        self._callbacks[client] = callback
-        self._queue.put_nowait(event)
-
-    def unregister(self, client: str) -&gt; None:
-        &#34;&#34;&#34;Unregister a client from the message bus.
-
-        &gt;&gt;&gt; async def callback(message):
-        ...     print(message)
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-        ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-        ...                  callback)
-        ...     bus.unregister(&#39;Client 1&#39;)
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        if client not in self._plugins:
-            return
-        event = Message(&#39;&#39;)
-        event[&#39;event&#39;] = &#39;unregistered&#39;
-        event[&#39;client&#39;] = client
-        del self._plugins[client]
-        self._send_reg.delete(client)
-        self._recv_reg.delete(client)
-        if client in self._callbacks:
-            del self._callbacks[client]
-        self._queue.put_nowait(event)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run the message bus forever.
-
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus_task = asyncio.create_task(bus.run())
-        ...     bus_task.cancel()
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        while True:
-            message = await self._queue.get()
-            if (&#39;target&#39; in message and
-                    message[&#39;target&#39;] == &#39;&#39; and
-                    &#39;command&#39; in message and
-                    message[&#39;command&#39;] == &#39;get clients&#39;):
-                for client in self._plugins:
-                    answer = Message(&#39;&#39;)
-                    answer[&#39;client&#39;] = client
-                    answer[&#39;plugin&#39;] = self._plugins[client]
-                    answer[&#39;sends&#39;] = self._send_reg.get_templates(client)
-                    answer[&#39;receives&#39;] = self._recv_reg.get_templates(client)
-                    await self._queue.put(answer)
-            for client in self._recv_reg.get(message):
-                await self._callbacks[client](message)
-            self._queue.task_done()
-
-    async def send(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Send a message to the message bus.
-
-        &gt;&gt;&gt; async def callback(message):
-        ...     print(f&#34;Got: {message}&#34;)
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-        ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-        ...                  callback)
-        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-        ...                  [{}],
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-        ...                  callback)
-        ...     bus_task = asyncio.create_task(bus.run())
-        ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,
-        ...                     &#39;k1&#39;: &#39;Test&#39;})
-        ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})
-        ...     try:
-        ...         await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,
-        ...                         &#39;k1&#39;: 42})
-        ...     except BusException as e:
-        ...         print(e)
-        ...     await asyncio.sleep(0)
-        ...     bus_task.cancel()
-        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;
-        not allowed for sender &#39;Client 1&#39;.
-        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}
-        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-        &#34;&#34;&#34;
-        assert isinstance(message[&#39;sender&#39;], str)
-        sender = message[&#39;sender&#39;]
-        if sender:
-            if not self._send_reg.check(sender, message):
-                raise BusException(f&#34;Message &#39;{message}&#39; not allowed for&#34;
-                                   f&#34; sender &#39;{sender}&#39;.&#34;)
-        await self._queue.put(message)</code></pre>
-</details>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-classes">Classes</h2>
-<dl>
-<dt id="controlpi.messagebus.Message"><code class="flex name class">
-<span>class <span class="ident">Message</span></span>
-<span>(</span><span>sender: str, init: Dict[str, Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]]] = None)</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Define arbitrary message.</p>
-<p>Messages are dictionaries with string keys and values that are strings,
-integers, floats, Booleans, dictionaries that recursively have string
-keys and values of any of these types, or lists with elements that have
-any of these types. These constraints are checked when setting key-value
-pairs of the message.</p>
-<p>A message has to have a sender, which is set by the constructor:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender')
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender'}
-</code></pre>
-<p>A dictionary can be given to the constructor:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender', {'key 1': 'value 1', 'key 2': 'value 2'})
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender', 'key 1': 'value 1', 'key 2': 'value 2'}
-</code></pre>
-<p>Or the message can be modified after construction:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender', {'key 1': 'value 1'})
-&gt;&gt;&gt; m['key 2'] = 'value 2'
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender', 'key 1': 'value 1', 'key 2': 'value 2'}
-</code></pre>
-<p>Initialise message.</p>
-<p>Message is initialised with given sender and possibly given
-key-value pairs:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender')
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender'}
-&gt;&gt;&gt; m = Message('Example sender', {'key 1': 'value 1'})
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender', 'key 1': 'value 1'}
-</code></pre>
-<p>The sender can be overwritten by the key-value pairs:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender', {'sender': 'Another sender'})
-&gt;&gt;&gt; print(m)
-{'sender': 'Another sender'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class Message(Dict[str, MessageValue]):
-    &#34;&#34;&#34;Define arbitrary message.
-
-    Messages are dictionaries with string keys and values that are strings,
-    integers, floats, Booleans, dictionaries that recursively have string
-    keys and values of any of these types, or lists with elements that have
-    any of these types. These constraints are checked when setting key-value
-    pairs of the message.
-
-    A message has to have a sender, which is set by the constructor:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;}
-
-    A dictionary can be given to the constructor:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-
-    Or the message can be modified after construction:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})
-    &gt;&gt;&gt; m[&#39;key 2&#39;] = &#39;value 2&#39;
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-    &#34;&#34;&#34;
-
-    def __init__(self, sender: str,
-                 init: Dict[str, MessageValue] = None) -&gt; None:
-        &#34;&#34;&#34;Initialise message.
-
-        Message is initialised with given sender and possibly given
-        key-value pairs:
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;}
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key 1&#39;: &#39;value 1&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;}
-
-        The sender can be overwritten by the key-value pairs:
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;sender&#39;: &#39;Another sender&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Another sender&#39;}
-        &#34;&#34;&#34;
-        if not isinstance(sender, str):
-            raise TypeError(f&#34;&#39;{sender}&#39; is not a valid sender name&#34;
-                            &#34; (not a string).&#34;)
-        self[&#39;sender&#39;] = sender
-        if init is not None:
-            self.update(init)
-
-    @staticmethod
-    def check_value(value: MessageValue) -&gt; bool:
-        &#34;&#34;&#34;Check recursively if a given value is valid.
-
-        None, strings, integers, floats and Booleans are valid:
-        &gt;&gt;&gt; Message.check_value(None)
-        True
-        &gt;&gt;&gt; Message.check_value(&#39;Spam&#39;)
-        True
-        &gt;&gt;&gt; Message.check_value(42)
-        True
-        &gt;&gt;&gt; Message.check_value(42.42)
-        True
-        &gt;&gt;&gt; Message.check_value(False)
-        True
-
-        Other basic types are not valid:
-        &gt;&gt;&gt; Message.check_value(b&#39;bytes&#39;)
-        False
-        &gt;&gt;&gt; Message.check_value(1j)
-        False
-
-        Dictionaries with string keys and recursively valid values are valid:
-        &gt;&gt;&gt; Message.check_value({&#39;str value&#39;: &#39;Spam&#39;, &#39;int value&#39;: 42,
-        ...                      &#39;float value&#39;: 42.42, &#39;bool value&#39;: False})
-        True
-
-        Empty dictionaries are valid:
-        &gt;&gt;&gt; Message.check_value({})
-        True
-
-        Dictionaries with other keys are not valid:
-        &gt;&gt;&gt; Message.check_value({42: &#39;int key&#39;})
-        False
-
-        Dictionaries with invalid values are not valid:
-        &gt;&gt;&gt; Message.check_value({&#39;complex value&#39;: 1j})
-        False
-
-        Lists with valid elements are valid:
-        &gt;&gt;&gt; Message.check_value([&#39;Spam&#39;, 42, 42.42, False])
-        True
-
-        Empty lists are valid:
-        &gt;&gt;&gt; Message.check_value([])
-        True
-
-        Lists with invalid elements are not valid:
-        &gt;&gt;&gt; Message.check_value([1j])
-        False
-        &#34;&#34;&#34;
-        if value is None:
-            return True
-        elif (isinstance(value, str) or isinstance(value, int) or
-                isinstance(value, float) or isinstance(value, bool)):
-            return True
-        elif isinstance(value, dict):
-            for key in value:
-                if not isinstance(key, str):
-                    return False
-                if not Message.check_value(value[key]):
-                    return False
-            return True
-        elif isinstance(value, list):
-            for element in value:
-                if not Message.check_value(element):
-                    return False
-            return True
-        return False
-
-    def __setitem__(self, key: str, value: MessageValue) -&gt; None:
-        &#34;&#34;&#34;Check key and value before putting pair into dict.
-
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m[&#39;key&#39;] = &#39;value&#39;
-        &gt;&gt;&gt; m[&#39;dict&#39;] = {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}
-        &gt;&gt;&gt; print(m)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;,
-         &#39;dict&#39;: {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}}
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m[42] = &#39;int key&#39;
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m[&#39;complex value&#39;] = 1j
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-        &#34;&#34;&#34;
-        if not isinstance(key, str):
-            raise TypeError(f&#34;&#39;{key}&#39; is not a valid key in Message&#34;
-                            &#34; (not a string).&#34;)
-        if not self.check_value(value):
-            raise TypeError(f&#34;&#39;{value}&#39; is not a valid value in Message.&#34;)
-        super().__setitem__(key, value)
-
-    def update(self, *args, **kwargs) -&gt; None:
-        &#34;&#34;&#34;Override update to use validity checks.
-
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m.update({&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-        &gt;&gt;&gt; m.update({42: &#39;int key&#39;})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m.update({&#39;complex value&#39;: 1j})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-
-        This is also used in __init__:
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})
-        &gt;&gt;&gt; print(m)
-        {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {42: &#39;int key&#39;})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;complex value&#39;: 1j})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-        &#34;&#34;&#34;
-        if args:
-            if len(args) &gt; 1:
-                raise TypeError(&#34;update expected at most 1 argument,&#34;
-                                f&#34; got {len(args)}&#34;)
-            other = dict(args[0])
-            for key in other:
-                self[key] = other[key]
-        for key in kwargs:
-            self[key] = kwargs[key]
-
-    def setdefault(self, key: str, value: MessageValue = None) -&gt; MessageValue:
-        &#34;&#34;&#34;Override setdefault to use validity checks.
-
-        &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 1&#39;)
-        &#39;value 1&#39;
-        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 2&#39;)
-        &#39;value 1&#39;
-        &gt;&gt;&gt; m.setdefault(42, &#39;int key&#39;)
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-        &gt;&gt;&gt; m.setdefault(&#39;complex value&#39;, 1j)
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;1j&#39; is not a valid value in Message.
-
-        But __setitem__ is not called if the key is already present:
-        &gt;&gt;&gt; m.setdefault(&#39;key&#39;, 1j)
-        &#39;value 1&#39;
-        &#34;&#34;&#34;
-        if key not in self:
-            self[key] = value
-        return self[key]</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li>builtins.dict</li>
-<li>typing.Generic</li>
-</ul>
-<h3>Static methods</h3>
-<dl>
-<dt id="controlpi.messagebus.Message.check_value"><code class="name flex">
-<span>def <span class="ident">check_value</span></span>(<span>value: Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]]) ‑> bool</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Check recursively if a given value is valid.</p>
-<p>None, strings, integers, floats and Booleans are valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value(None)
-True
-&gt;&gt;&gt; Message.check_value('Spam')
-True
-&gt;&gt;&gt; Message.check_value(42)
-True
-&gt;&gt;&gt; Message.check_value(42.42)
-True
-&gt;&gt;&gt; Message.check_value(False)
-True
-</code></pre>
-<p>Other basic types are not valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value(b'bytes')
-False
-&gt;&gt;&gt; Message.check_value(1j)
-False
-</code></pre>
-<p>Dictionaries with string keys and recursively valid values are valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value({'str value': 'Spam', 'int value': 42,
-...                      'float value': 42.42, 'bool value': False})
-True
-</code></pre>
-<p>Empty dictionaries are valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value({})
-True
-</code></pre>
-<p>Dictionaries with other keys are not valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value({42: 'int key'})
-False
-</code></pre>
-<p>Dictionaries with invalid values are not valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value({'complex value': 1j})
-False
-</code></pre>
-<p>Lists with valid elements are valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value(['Spam', 42, 42.42, False])
-True
-</code></pre>
-<p>Empty lists are valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value([])
-True
-</code></pre>
-<p>Lists with invalid elements are not valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; Message.check_value([1j])
-False
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">@staticmethod
-def check_value(value: MessageValue) -&gt; bool:
-    &#34;&#34;&#34;Check recursively if a given value is valid.
-
-    None, strings, integers, floats and Booleans are valid:
-    &gt;&gt;&gt; Message.check_value(None)
-    True
-    &gt;&gt;&gt; Message.check_value(&#39;Spam&#39;)
-    True
-    &gt;&gt;&gt; Message.check_value(42)
-    True
-    &gt;&gt;&gt; Message.check_value(42.42)
-    True
-    &gt;&gt;&gt; Message.check_value(False)
-    True
-
-    Other basic types are not valid:
-    &gt;&gt;&gt; Message.check_value(b&#39;bytes&#39;)
-    False
-    &gt;&gt;&gt; Message.check_value(1j)
-    False
-
-    Dictionaries with string keys and recursively valid values are valid:
-    &gt;&gt;&gt; Message.check_value({&#39;str value&#39;: &#39;Spam&#39;, &#39;int value&#39;: 42,
-    ...                      &#39;float value&#39;: 42.42, &#39;bool value&#39;: False})
-    True
-
-    Empty dictionaries are valid:
-    &gt;&gt;&gt; Message.check_value({})
-    True
-
-    Dictionaries with other keys are not valid:
-    &gt;&gt;&gt; Message.check_value({42: &#39;int key&#39;})
-    False
-
-    Dictionaries with invalid values are not valid:
-    &gt;&gt;&gt; Message.check_value({&#39;complex value&#39;: 1j})
-    False
-
-    Lists with valid elements are valid:
-    &gt;&gt;&gt; Message.check_value([&#39;Spam&#39;, 42, 42.42, False])
-    True
-
-    Empty lists are valid:
-    &gt;&gt;&gt; Message.check_value([])
-    True
-
-    Lists with invalid elements are not valid:
-    &gt;&gt;&gt; Message.check_value([1j])
-    False
-    &#34;&#34;&#34;
-    if value is None:
-        return True
-    elif (isinstance(value, str) or isinstance(value, int) or
-            isinstance(value, float) or isinstance(value, bool)):
-        return True
-    elif isinstance(value, dict):
-        for key in value:
-            if not isinstance(key, str):
-                return False
-            if not Message.check_value(value[key]):
-                return False
-        return True
-    elif isinstance(value, list):
-        for element in value:
-            if not Message.check_value(element):
-                return False
-        return True
-    return False</code></pre>
-</details>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi.messagebus.Message.update"><code class="name flex">
-<span>def <span class="ident">update</span></span>(<span>self, *args, **kwargs) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Override update to use validity checks.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender')
-&gt;&gt;&gt; m.update({'key 1': 'value 1', 'key 2': 'value 2'})
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender', 'key 1': 'value 1', 'key 2': 'value 2'}
-&gt;&gt;&gt; m.update({42: 'int key'})
-Traceback (most recent call last):
-  ...
-TypeError: '42' is not a valid key in Message (not a string).
-&gt;&gt;&gt; m.update({'complex value': 1j})
-Traceback (most recent call last):
-  ...
-TypeError: '1j' is not a valid value in Message.
-</code></pre>
-<p>This is also used in <strong>init</strong>:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender', {'key': 'value'})
-&gt;&gt;&gt; print(m)
-{'sender': 'Example sender', 'key': 'value'}
-&gt;&gt;&gt; m = Message('Example sender', {42: 'int key'})
-Traceback (most recent call last):
-  ...
-TypeError: '42' is not a valid key in Message (not a string).
-&gt;&gt;&gt; m = Message('Example sender', {'complex value': 1j})
-Traceback (most recent call last):
-  ...
-TypeError: '1j' is not a valid value in Message.
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def update(self, *args, **kwargs) -&gt; None:
-    &#34;&#34;&#34;Override update to use validity checks.
-
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-    &gt;&gt;&gt; m.update({&#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;})
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key 1&#39;: &#39;value 1&#39;, &#39;key 2&#39;: &#39;value 2&#39;}
-    &gt;&gt;&gt; m.update({42: &#39;int key&#39;})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-    &gt;&gt;&gt; m.update({&#39;complex value&#39;: 1j})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;1j&#39; is not a valid value in Message.
-
-    This is also used in __init__:
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;key&#39;: &#39;value&#39;})
-    &gt;&gt;&gt; print(m)
-    {&#39;sender&#39;: &#39;Example sender&#39;, &#39;key&#39;: &#39;value&#39;}
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {42: &#39;int key&#39;})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;, {&#39;complex value&#39;: 1j})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;1j&#39; is not a valid value in Message.
-    &#34;&#34;&#34;
-    if args:
-        if len(args) &gt; 1:
-            raise TypeError(&#34;update expected at most 1 argument,&#34;
-                            f&#34; got {len(args)}&#34;)
-        other = dict(args[0])
-        for key in other:
-            self[key] = other[key]
-    for key in kwargs:
-        self[key] = kwargs[key]</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.Message.setdefault"><code class="name flex">
-<span>def <span class="ident">setdefault</span></span>(<span>self, key: str, value: Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]] = None) ‑> Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]]</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Override setdefault to use validity checks.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example sender')
-&gt;&gt;&gt; m.setdefault('key', 'value 1')
-'value 1'
-&gt;&gt;&gt; m.setdefault('key', 'value 2')
-'value 1'
-&gt;&gt;&gt; m.setdefault(42, 'int key')
-Traceback (most recent call last):
-  ...
-TypeError: '42' is not a valid key in Message (not a string).
-&gt;&gt;&gt; m.setdefault('complex value', 1j)
-Traceback (most recent call last):
-  ...
-TypeError: '1j' is not a valid value in Message.
-</code></pre>
-<p>But <strong>setitem</strong> is not called if the key is already present:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m.setdefault('key', 1j)
-'value 1'
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def setdefault(self, key: str, value: MessageValue = None) -&gt; MessageValue:
-    &#34;&#34;&#34;Override setdefault to use validity checks.
-
-    &gt;&gt;&gt; m = Message(&#39;Example sender&#39;)
-    &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 1&#39;)
-    &#39;value 1&#39;
-    &gt;&gt;&gt; m.setdefault(&#39;key&#39;, &#39;value 2&#39;)
-    &#39;value 1&#39;
-    &gt;&gt;&gt; m.setdefault(42, &#39;int key&#39;)
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;42&#39; is not a valid key in Message (not a string).
-    &gt;&gt;&gt; m.setdefault(&#39;complex value&#39;, 1j)
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;1j&#39; is not a valid value in Message.
-
-    But __setitem__ is not called if the key is already present:
-    &gt;&gt;&gt; m.setdefault(&#39;key&#39;, 1j)
-    &#39;value 1&#39;
-    &#34;&#34;&#34;
-    if key not in self:
-        self[key] = value
-    return self[key]</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplate"><code class="flex name class">
-<span>class <span class="ident">MessageTemplate</span></span>
-<span>(</span><span>init: Dict[str, Union[bool, Dict[str, Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]]]]] = None)</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Define a message template.</p>
-<p>A message template is a mapping from string keys to JSON schemas as
-values:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key 1': {'const': 'value'},
-...                      'key 2': {'type': 'string'}})
-&gt;&gt;&gt; t['key 3'] = {'type': 'object',
-...               'properties': {'key 1': {'type': 'number'},
-...                              'key 2': True}}
-</code></pre>
-<p>A message template matches a message if all keys of the template are
-contained in the message and the values in the message validate against
-the respective schemas:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t.check(Message('Example Sender',
-...                 {'key 1': 'value', 'key 2': 'some string',
-...                  'key 3': {'key 1': 42, 'key 2': None}}))
-True
-</code></pre>
-<p>An empty mapping therefore matches all messages:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate()
-&gt;&gt;&gt; t.check(Message('Example Sender', {'arbitrary': 'content'}))
-True
-</code></pre>
-<p>Initialise message.</p>
-<p>Template is initialised empty or with given key-value pairs:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate()
-&gt;&gt;&gt; print(t)
-{}
-&gt;&gt;&gt; t = MessageTemplate({'key': {'const': 'value'}})
-&gt;&gt;&gt; print(t)
-{'key': {'const': 'value'}}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class MessageTemplate(Dict[str, JSONSchema]):
-    &#34;&#34;&#34;Define a message template.
-
-    A message template is a mapping from string keys to JSON schemas as
-    values:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-    ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;}})
-    &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,
-    ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-    ...                              &#39;key 2&#39;: True}}
-
-    A message template matches a message if all keys of the template are
-    contained in the message and the values in the message validate against
-    the respective schemas:
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-    ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42, &#39;key 2&#39;: None}}))
-    True
-
-    An empty mapping therefore matches all messages:
-    &gt;&gt;&gt; t = MessageTemplate()
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;arbitrary&#39;: &#39;content&#39;}))
-    True
-    &#34;&#34;&#34;
-
-    def __init__(self, init: Dict[str, JSONSchema] = None) -&gt; None:
-        &#34;&#34;&#34;Initialise message.
-
-        Template is initialised empty or with given key-value pairs:
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; print(t)
-        {}
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})
-        &gt;&gt;&gt; print(t)
-        {&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}
-        &#34;&#34;&#34;
-        if init is not None:
-            self.update(init)
-
-    @staticmethod
-    def from_message(message: Message) -&gt; &#39;MessageTemplate&#39;:
-        &#34;&#34;&#34;Create template from message.
-
-        Template witch constant schemas is created from message:
-        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;})
-        &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-        &gt;&gt;&gt; print(t)
-        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}
-        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},
-        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})
-        &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},
-         &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,
-                  &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},
-                                 &#39;float&#39;: {&#39;const&#39;: 42.42}}},
-         &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,
-                  &#39;items&#39;: [{&#39;const&#39;: None},
-                            {&#39;const&#39;: True},
-                            {&#39;const&#39;: &#39;string&#39;}]}}
-
-        This is especially useful for clients that send certain fully
-        predefined messages, where the message is given in the configuration
-        and the template for the registration can be constructed by this
-        method.
-        &#34;&#34;&#34;
-        def schema_from_value(value: MessageValue) -&gt; JSONSchema:
-            schema: JSONSchema = False
-            if value is None:
-                schema = {&#39;const&#39;: None}
-            elif (isinstance(value, str) or isinstance(value, int) or
-                    isinstance(value, float) or isinstance(value, bool)):
-                schema = {&#39;const&#39;: value}
-            elif isinstance(value, dict):
-                properties = {}
-                for inner_key in value:
-                    inner_value: Message = value[inner_key]
-                    properties[inner_key] = schema_from_value(inner_value)
-                schema = {&#39;type&#39;: &#39;object&#39;,
-                          &#39;properties&#39;: properties}
-            elif isinstance(value, list):
-                schema = {&#39;type&#39;: &#39;array&#39;,
-                          &#39;items&#39;: [schema_from_value(element)
-                                    for element in value]}
-            return schema
-        template = MessageTemplate()
-        for key in message:
-            template[key] = schema_from_value(message[key])
-        return template
-
-    def __setitem__(self, key: str, value: JSONSchema) -&gt; None:
-        &#34;&#34;&#34;Check key and value before putting pair into dict.
-
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; t[&#39;key 1&#39;] = {&#39;const&#39;: &#39;value&#39;}
-        &gt;&gt;&gt; t[&#39;key 2&#39;] = {&#39;type&#39;: &#39;string&#39;}
-        &gt;&gt;&gt; t[&#39;key 3&#39;] = {&#39;type&#39;: &#39;object&#39;,
-        ...               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                              &#39;key 2&#39;: True}}
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}}
-        &gt;&gt;&gt; t[42] = {&#39;const&#39;: &#39;int key&#39;}
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t[&#39;key&#39;] = &#39;schema&#39;  # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-        &#34;&#34;&#34;
-        if not isinstance(key, str):
-            raise TypeError(f&#34;&#39;{key}&#39; is not a valid key in MessageTemplate&#34;
-                            &#34; (not a string).&#34;)
-        try:
-            jsonschema.Draft7Validator.check_schema(value)
-            # Draft7Validator is hardcoded, because _LATEST_VERSION is
-            # non-public in jsonschema and we also perhaps do not want to
-            # upgrade automatically.
-        except jsonschema.exceptions.SchemaError:
-            raise TypeError(f&#34;&#39;{value}&#39; is not a valid value in&#34;
-                            &#34; MessageTemplate (not a valid JSON schema).&#34;)
-        super().__setitem__(key, value)
-
-    def update(self, *args, **kwargs) -&gt; None:
-        &#34;&#34;&#34;Override update to use validity checks.
-
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; t.update({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-        ...           &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-        ...           &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-        ...                     &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                    &#39;key 2&#39;: True}}})
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}}
-        &gt;&gt;&gt; t.update({42: {&#39;const&#39;: &#39;int key&#39;}})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t.update({&#39;key&#39;: &#39;schema&#39;})  # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-
-        This is also used in __init__:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-        ...                                &#39;properties&#39;: {
-        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                    &#39;key 2&#39;: True}}})
-        &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-        {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-         &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}}
-        &gt;&gt;&gt; t = MessageTemplate({42: {&#39;const&#39;: &#39;int key&#39;}})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: &#39;schema&#39;})
-        ... # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-        &#34;&#34;&#34;
-        if args:
-            if len(args) &gt; 1:
-                raise TypeError(&#34;update expected at most 1 argument,&#34;
-                                f&#34; got {len(args)}&#34;)
-            other = dict(args[0])
-            for key in other:
-                self[key] = other[key]
-        for key in kwargs:
-            self[key] = kwargs[key]
-
-    def setdefault(self, key: str, value: JSONSchema = None) -&gt; JSONSchema:
-        &#34;&#34;&#34;Override setdefault to use validity checks.
-
-        &gt;&gt;&gt; t = MessageTemplate()
-        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, {&#39;const&#39;: &#39;value&#39;})
-        {&#39;const&#39;: &#39;value&#39;}
-        &gt;&gt;&gt; t.setdefault(&#39;key 2&#39;, {&#39;type&#39;: &#39;string&#39;})
-        {&#39;type&#39;: &#39;string&#39;}
-        &gt;&gt;&gt; t.setdefault(&#39;key 3&#39;, {&#39;type&#39;: &#39;object&#39;,
-        ...                        &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                       &#39;key 2&#39;: True}})
-        ... # doctest: +NORMALIZE_WHITESPACE
-        {&#39;type&#39;: &#39;object&#39;,
-                   &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                  &#39;key 2&#39;: True}}
-        &gt;&gt;&gt; t.setdefault(42, {&#39;const&#39;: &#39;int key&#39;})
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-        &gt;&gt;&gt; t.setdefault(&#39;key&#39;, &#39;schema&#39;)  # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-          ...
-        TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-        (not a valid JSON schema).
-
-        But __setitem__ is not called if the key is already present:
-        &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, &#39;schema&#39;)
-        {&#39;const&#39;: &#39;value&#39;}
-        &#34;&#34;&#34;
-        if key not in self:
-            if value is not None:
-                self[key] = value
-            else:
-                self[key] = True
-        return self[key]
-
-    def check(self, message: Message) -&gt; bool:
-        &#34;&#34;&#34;Check message against this template.
-
-        Constant values have to match exactly:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;other value&#39;}))
-        False
-
-        But for integers, floats with the same value are also valid:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: 42}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))
-        True
-
-        Type integer is valid for floats with zero fractional part, but
-        not by floats with non-zero fractional part:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;integer&#39;}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))
-        False
-
-        Type number is valid for arbitrary ints or floats:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;number&#39;}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-        True
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))
-        True
-
-        All keys in template have to be present in message:
-        &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-        ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-        ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-        ...                                &#39;properties&#39;: {
-        ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-        ...                                    &#39;key 2&#39;: True,
-        ...                                    &#39;key 3&#39;: False}}})
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;}))
-        False
-
-        But for nested objects their properties do not necessarily have
-        to be present:
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-        ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42}}))
-        True
-
-        Schema True matches everything (even None):
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-        ...                  &#39;key 3&#39;: {&#39;key 2&#39;: None}}))
-        True
-
-        Schema False matches nothing:
-        &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-        ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-        ...                  &#39;key 3&#39;: {&#39;key 3&#39;: True}}))
-        False
-
-        Message is valid for the constant template created from it:
-        &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},
-        ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})
-        &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-        &gt;&gt;&gt; t.check(m)
-        True
-        &#34;&#34;&#34;
-        for key in self:
-            if key not in message:
-                return False
-            else:
-                validator = jsonschema.Draft7Validator(self[key])
-                for error in validator.iter_errors(message[key]):
-                    return False
-        return True</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li>builtins.dict</li>
-<li>typing.Generic</li>
-</ul>
-<h3>Static methods</h3>
-<dl>
-<dt id="controlpi.messagebus.MessageTemplate.from_message"><code class="name flex">
-<span>def <span class="ident">from_message</span></span>(<span>message: <a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a>) ‑> <a title="controlpi.messagebus.MessageTemplate" href="#controlpi.messagebus.MessageTemplate">MessageTemplate</a></span>
-</code></dt>
-<dd>
-<div class="desc"><p>Create template from message.</p>
-<p>Template witch constant schemas is created from message:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example Sender', {'key': 'value'})
-&gt;&gt;&gt; t = MessageTemplate.from_message(m)
-&gt;&gt;&gt; print(t)
-{'sender': {'const': 'Example Sender'}, 'key': {'const': 'value'}}
-&gt;&gt;&gt; m = Message('Example Sender', {'dict': {'int': 42, 'float': 42.42},
-...                                'list': [None, True, 'string']})
-&gt;&gt;&gt; t = MessageTemplate.from_message(m)
-&gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-{'sender': {'const': 'Example Sender'},
- 'dict': {'type': 'object',
-          'properties': {'int': {'const': 42},
-                         'float': {'const': 42.42}}},
- 'list': {'type': 'array',
-          'items': [{'const': None},
-                    {'const': True},
-                    {'const': 'string'}]}}
-</code></pre>
-<p>This is especially useful for clients that send certain fully
-predefined messages, where the message is given in the configuration
-and the template for the registration can be constructed by this
-method.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">@staticmethod
-def from_message(message: Message) -&gt; &#39;MessageTemplate&#39;:
-    &#34;&#34;&#34;Create template from message.
-
-    Template witch constant schemas is created from message:
-    &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;})
-    &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-    &gt;&gt;&gt; print(t)
-    {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;}, &#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}}
-    &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},
-    ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})
-    &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-    &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-    {&#39;sender&#39;: {&#39;const&#39;: &#39;Example Sender&#39;},
-     &#39;dict&#39;: {&#39;type&#39;: &#39;object&#39;,
-              &#39;properties&#39;: {&#39;int&#39;: {&#39;const&#39;: 42},
-                             &#39;float&#39;: {&#39;const&#39;: 42.42}}},
-     &#39;list&#39;: {&#39;type&#39;: &#39;array&#39;,
-              &#39;items&#39;: [{&#39;const&#39;: None},
-                        {&#39;const&#39;: True},
-                        {&#39;const&#39;: &#39;string&#39;}]}}
-
-    This is especially useful for clients that send certain fully
-    predefined messages, where the message is given in the configuration
-    and the template for the registration can be constructed by this
-    method.
-    &#34;&#34;&#34;
-    def schema_from_value(value: MessageValue) -&gt; JSONSchema:
-        schema: JSONSchema = False
-        if value is None:
-            schema = {&#39;const&#39;: None}
-        elif (isinstance(value, str) or isinstance(value, int) or
-                isinstance(value, float) or isinstance(value, bool)):
-            schema = {&#39;const&#39;: value}
-        elif isinstance(value, dict):
-            properties = {}
-            for inner_key in value:
-                inner_value: Message = value[inner_key]
-                properties[inner_key] = schema_from_value(inner_value)
-            schema = {&#39;type&#39;: &#39;object&#39;,
-                      &#39;properties&#39;: properties}
-        elif isinstance(value, list):
-            schema = {&#39;type&#39;: &#39;array&#39;,
-                      &#39;items&#39;: [schema_from_value(element)
-                                for element in value]}
-        return schema
-    template = MessageTemplate()
-    for key in message:
-        template[key] = schema_from_value(message[key])
-    return template</code></pre>
-</details>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi.messagebus.MessageTemplate.update"><code class="name flex">
-<span>def <span class="ident">update</span></span>(<span>self, *args, **kwargs) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Override update to use validity checks.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate()
-&gt;&gt;&gt; t.update({'key 1': {'const': 'value'},
-...           'key 2': {'type': 'string'},
-...           'key 3': {'type': 'object',
-...                     'properties': {'key 1': {'type': 'number'},
-...                                    'key 2': True}}})
-&gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-{'key 1': {'const': 'value'}, 'key 2': {'type': 'string'},
- 'key 3': {'type': 'object',
-           'properties': {'key 1': {'type': 'number'},
-                          'key 2': True}}}
-&gt;&gt;&gt; t.update({42: {'const': 'int key'}})
-Traceback (most recent call last):
-  ...
-TypeError: '42' is not a valid key in MessageTemplate (not a string).
-&gt;&gt;&gt; t.update({'key': 'schema'})  # doctest: +NORMALIZE_WHITESPACE
-Traceback (most recent call last):
-  ...
-TypeError: 'schema' is not a valid value in MessageTemplate
-(not a valid JSON schema).
-</code></pre>
-<p>This is also used in <strong>init</strong>:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key 1': {'const': 'value'},
-...                      'key 2': {'type': 'string'},
-...                      'key 3': {'type': 'object',
-...                                'properties': {
-...                                    'key 1': {'type': 'number'},
-...                                    'key 2': True}}})
-&gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-{'key 1': {'const': 'value'}, 'key 2': {'type': 'string'},
- 'key 3': {'type': 'object',
-           'properties': {'key 1': {'type': 'number'},
-                          'key 2': True}}}
-&gt;&gt;&gt; t = MessageTemplate({42: {'const': 'int key'}})
-Traceback (most recent call last):
-  ...
-TypeError: '42' is not a valid key in MessageTemplate (not a string).
-&gt;&gt;&gt; t = MessageTemplate({'key': 'schema'})
-... # doctest: +NORMALIZE_WHITESPACE
-Traceback (most recent call last):
-  ...
-TypeError: 'schema' is not a valid value in MessageTemplate
-(not a valid JSON schema).
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def update(self, *args, **kwargs) -&gt; None:
-    &#34;&#34;&#34;Override update to use validity checks.
-
-    &gt;&gt;&gt; t = MessageTemplate()
-    &gt;&gt;&gt; t.update({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-    ...           &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-    ...           &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-    ...                     &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-    ...                                    &#39;key 2&#39;: True}}})
-    &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-    {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-     &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                              &#39;key 2&#39;: True}}}
-    &gt;&gt;&gt; t.update({42: {&#39;const&#39;: &#39;int key&#39;}})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-    &gt;&gt;&gt; t.update({&#39;key&#39;: &#39;schema&#39;})  # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-    (not a valid JSON schema).
-
-    This is also used in __init__:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-    ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-    ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-    ...                                &#39;properties&#39;: {
-    ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-    ...                                    &#39;key 2&#39;: True}}})
-    &gt;&gt;&gt; print(t)  # doctest: +NORMALIZE_WHITESPACE
-    {&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;}, &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-     &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                              &#39;key 2&#39;: True}}}
-    &gt;&gt;&gt; t = MessageTemplate({42: {&#39;const&#39;: &#39;int key&#39;}})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: &#39;schema&#39;})
-    ... # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-    (not a valid JSON schema).
-    &#34;&#34;&#34;
-    if args:
-        if len(args) &gt; 1:
-            raise TypeError(&#34;update expected at most 1 argument,&#34;
-                            f&#34; got {len(args)}&#34;)
-        other = dict(args[0])
-        for key in other:
-            self[key] = other[key]
-    for key in kwargs:
-        self[key] = kwargs[key]</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplate.setdefault"><code class="name flex">
-<span>def <span class="ident">setdefault</span></span>(<span>self, key: str, value: Union[bool, Dict[str, Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]]]] = None) ‑> Union[bool, Dict[str, Union[NoneType, str, int, float, bool, Dict[str, Any], List[Any]]]]</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Override setdefault to use validity checks.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate()
-&gt;&gt;&gt; t.setdefault('key 1', {'const': 'value'})
-{'const': 'value'}
-&gt;&gt;&gt; t.setdefault('key 2', {'type': 'string'})
-{'type': 'string'}
-&gt;&gt;&gt; t.setdefault('key 3', {'type': 'object',
-...                        'properties': {'key 1': {'type': 'number'},
-...                                       'key 2': True}})
-... # doctest: +NORMALIZE_WHITESPACE
-{'type': 'object',
-           'properties': {'key 1': {'type': 'number'},
-                          'key 2': True}}
-&gt;&gt;&gt; t.setdefault(42, {'const': 'int key'})
-Traceback (most recent call last):
-  ...
-TypeError: '42' is not a valid key in MessageTemplate (not a string).
-&gt;&gt;&gt; t.setdefault('key', 'schema')  # doctest: +NORMALIZE_WHITESPACE
-Traceback (most recent call last):
-  ...
-TypeError: 'schema' is not a valid value in MessageTemplate
-(not a valid JSON schema).
-</code></pre>
-<p>But <strong>setitem</strong> is not called if the key is already present:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t.setdefault('key 1', 'schema')
-{'const': 'value'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def setdefault(self, key: str, value: JSONSchema = None) -&gt; JSONSchema:
-    &#34;&#34;&#34;Override setdefault to use validity checks.
-
-    &gt;&gt;&gt; t = MessageTemplate()
-    &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, {&#39;const&#39;: &#39;value&#39;})
-    {&#39;const&#39;: &#39;value&#39;}
-    &gt;&gt;&gt; t.setdefault(&#39;key 2&#39;, {&#39;type&#39;: &#39;string&#39;})
-    {&#39;type&#39;: &#39;string&#39;}
-    &gt;&gt;&gt; t.setdefault(&#39;key 3&#39;, {&#39;type&#39;: &#39;object&#39;,
-    ...                        &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-    ...                                       &#39;key 2&#39;: True}})
-    ... # doctest: +NORMALIZE_WHITESPACE
-    {&#39;type&#39;: &#39;object&#39;,
-               &#39;properties&#39;: {&#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-                              &#39;key 2&#39;: True}}
-    &gt;&gt;&gt; t.setdefault(42, {&#39;const&#39;: &#39;int key&#39;})
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;42&#39; is not a valid key in MessageTemplate (not a string).
-    &gt;&gt;&gt; t.setdefault(&#39;key&#39;, &#39;schema&#39;)  # doctest: +NORMALIZE_WHITESPACE
-    Traceback (most recent call last):
-      ...
-    TypeError: &#39;schema&#39; is not a valid value in MessageTemplate
-    (not a valid JSON schema).
-
-    But __setitem__ is not called if the key is already present:
-    &gt;&gt;&gt; t.setdefault(&#39;key 1&#39;, &#39;schema&#39;)
-    {&#39;const&#39;: &#39;value&#39;}
-    &#34;&#34;&#34;
-    if key not in self:
-        if value is not None:
-            self[key] = value
-        else:
-            self[key] = True
-    return self[key]</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplate.check"><code class="name flex">
-<span>def <span class="ident">check</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a>) ‑> bool</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Check message against this template.</p>
-<p>Constant values have to match exactly:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key': {'const': 'value'}})
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 'value'}))
-True
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 'other value'}))
-False
-</code></pre>
-<p>But for integers, floats with the same value are also valid:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key': {'const': 42}})
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42}))
-True
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42.0}))
-True
-</code></pre>
-<p>Type integer is valid for floats with zero fractional part, but
-not by floats with non-zero fractional part:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key': {'type': 'integer'}})
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42}))
-True
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42.0}))
-True
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42.42}))
-False
-</code></pre>
-<p>Type number is valid for arbitrary ints or floats:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key': {'type': 'number'}})
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42}))
-True
-&gt;&gt;&gt; t.check(Message('Example Sender', {'key': 42.42}))
-True
-</code></pre>
-<p>All keys in template have to be present in message:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t = MessageTemplate({'key 1': {'const': 'value'},
-...                      'key 2': {'type': 'string'},
-...                      'key 3': {'type': 'object',
-...                                'properties': {
-...                                    'key 1': {'type': 'number'},
-...                                    'key 2': True,
-...                                    'key 3': False}}})
-&gt;&gt;&gt; t.check(Message('Example Sender',
-...                 {'key 1': 'value', 'key 2': 'some string'}))
-False
-</code></pre>
-<p>But for nested objects their properties do not necessarily have
-to be present:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t.check(Message('Example Sender',
-...                 {'key 1': 'value', 'key 2': 'some string',
-...                  'key 3': {'key 1': 42}}))
-True
-</code></pre>
-<p>Schema True matches everything (even None):</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t.check(Message('Example Sender',
-...                 {'key 1': 'value', 'key 2': 'some string',
-...                  'key 3': {'key 2': None}}))
-True
-</code></pre>
-<p>Schema False matches nothing:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; t.check(Message('Example Sender',
-...                 {'key 1': 'value', 'key 2': 'some string',
-...                  'key 3': {'key 3': True}}))
-False
-</code></pre>
-<p>Message is valid for the constant template created from it:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; m = Message('Example Sender', {'dict': {'int': 42, 'float': 42.42},
-...                                'list': [None, True, 'string']})
-&gt;&gt;&gt; t = MessageTemplate.from_message(m)
-&gt;&gt;&gt; t.check(m)
-True
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def check(self, message: Message) -&gt; bool:
-    &#34;&#34;&#34;Check message against this template.
-
-    Constant values have to match exactly:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: &#39;value&#39;}})
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;value&#39;}))
-    True
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: &#39;other value&#39;}))
-    False
-
-    But for integers, floats with the same value are also valid:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;const&#39;: 42}})
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-    True
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))
-    True
-
-    Type integer is valid for floats with zero fractional part, but
-    not by floats with non-zero fractional part:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;integer&#39;}})
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-    True
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.0}))
-    True
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))
-    False
-
-    Type number is valid for arbitrary ints or floats:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key&#39;: {&#39;type&#39;: &#39;number&#39;}})
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42}))
-    True
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;, {&#39;key&#39;: 42.42}))
-    True
-
-    All keys in template have to be present in message:
-    &gt;&gt;&gt; t = MessageTemplate({&#39;key 1&#39;: {&#39;const&#39;: &#39;value&#39;},
-    ...                      &#39;key 2&#39;: {&#39;type&#39;: &#39;string&#39;},
-    ...                      &#39;key 3&#39;: {&#39;type&#39;: &#39;object&#39;,
-    ...                                &#39;properties&#39;: {
-    ...                                    &#39;key 1&#39;: {&#39;type&#39;: &#39;number&#39;},
-    ...                                    &#39;key 2&#39;: True,
-    ...                                    &#39;key 3&#39;: False}}})
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;}))
-    False
-
-    But for nested objects their properties do not necessarily have
-    to be present:
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-    ...                  &#39;key 3&#39;: {&#39;key 1&#39;: 42}}))
-    True
-
-    Schema True matches everything (even None):
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-    ...                  &#39;key 3&#39;: {&#39;key 2&#39;: None}}))
-    True
-
-    Schema False matches nothing:
-    &gt;&gt;&gt; t.check(Message(&#39;Example Sender&#39;,
-    ...                 {&#39;key 1&#39;: &#39;value&#39;, &#39;key 2&#39;: &#39;some string&#39;,
-    ...                  &#39;key 3&#39;: {&#39;key 3&#39;: True}}))
-    False
-
-    Message is valid for the constant template created from it:
-    &gt;&gt;&gt; m = Message(&#39;Example Sender&#39;, {&#39;dict&#39;: {&#39;int&#39;: 42, &#39;float&#39;: 42.42},
-    ...                                &#39;list&#39;: [None, True, &#39;string&#39;]})
-    &gt;&gt;&gt; t = MessageTemplate.from_message(m)
-    &gt;&gt;&gt; t.check(m)
-    True
-    &#34;&#34;&#34;
-    for key in self:
-        if key not in message:
-            return False
-        else:
-            validator = jsonschema.Draft7Validator(self[key])
-            for error in validator.iter_errors(message[key]):
-                return False
-    return True</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplateRegistry"><code class="flex name class">
-<span>class <span class="ident">MessageTemplateRegistry</span></span>
-</code></dt>
-<dd>
-<div class="desc"><p>Manage a collection of message templates with registered clients.</p>
-<p>A new MessageTemplateRegistry is created by:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-</code></pre>
-<p>Client names (strings) can be registered for message templates, which
-are mappings from keys to JSON schemas:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'C 1')
-</code></pre>
-<p>The check function checks if the templates registered for a client
-match a given message:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 1', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: True
-{'k1': 'v1', 'k2': 2}: True
-{'k1': 'v2', 'k2': 'v1'}: False
-{'k1': 'v2', 'k2': 2}: False
-</code></pre>
-<p>Clients can be registered for values validating against arbitrary JSON
-schemas, e.g. all values of a certain type:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'}, 'k2': {'type': 'string'}}, 'C 2')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 2', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: False
-{'k1': 'v1', 'k2': 2}: False
-{'k1': 'v2', 'k2': 'v1'}: True
-{'k1': 'v2', 'k2': 2}: False
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'}, 'k2': {'type': 'integer'}}, 'C 3')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 3', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: False
-{'k1': 'v1', 'k2': 2}: False
-{'k1': 'v2', 'k2': 'v1'}: False
-{'k1': 'v2', 'k2': 2}: True
-</code></pre>
-<p>The order of key-value pairs does not have to match the order in the
-messages and keys can be left out:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r.insert({'k2': {'const': 2}}, 'C 4')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 4', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: False
-{'k1': 'v1', 'k2': 2}: True
-{'k1': 'v2', 'k2': 'v1'}: False
-{'k1': 'v2', 'k2': 2}: True
-</code></pre>
-<p>A registration for an empty template matches all messages:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r.insert({}, 'C 5')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 5', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: True
-{'k1': 'v1', 'k2': 2}: True
-{'k1': 'v2', 'k2': 'v1'}: True
-{'k1': 'v2', 'k2': 2}: True
-</code></pre>
-<p>A client can be registered for multiple templates:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'C 6')
-&gt;&gt;&gt; r.insert({'k2': {'const': 'v1'}}, 'C 6')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 6', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: True
-{'k1': 'v1', 'k2': 2}: True
-{'k1': 'v2', 'k2': 'v1'}: True
-{'k1': 'v2', 'k2': 2}: False
-</code></pre>
-<p>Clients can be deregistered again (the result is False if the registry
-is empty after the deletion):</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'C 7')
-&gt;&gt;&gt; r.delete('C 7')
-True
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.check('C 7', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: False
-{'k1': 'v1', 'k2': 2}: False
-{'k1': 'v2', 'k2': 'v1'}: False
-{'k1': 'v2', 'k2': 2}: False
-</code></pre>
-<p>The get function returns all clients with registered templates matching
-a given message:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 2},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 2}]:
-...     print(f&quot;{m}: {r.get(m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: ['C 5', 'C 1', 'C 6']
-{'k1': 'v1', 'k2': 2}: ['C 5', 'C 1', 'C 6', 'C 4']
-{'k1': 'v2', 'k2': 'v1'}: ['C 5', 'C 2', 'C 6']
-{'k1': 'v2', 'k2': 2}: ['C 5', 'C 3', 'C 4']
-</code></pre>
-<p>The get_templates function returns all templates for a given client:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; for c in ['C 1', 'C 2', 'C 3', 'C 4', 'C 5', 'C 6']:
-...     print(f&quot;{c}: {r.get_templates(c)}&quot;)
-C 1: [{'k1': {'const': 'v1'}}]
-C 2: [{'k1': {'const': 'v2'}, 'k2': {'type': 'string'}}]
-C 3: [{'k1': {'const': 'v2'}, 'k2': {'type': 'integer'}}]
-C 4: [{'k2': {'const': 2}}]
-C 5: [{}]
-C 6: [{'k1': {'const': 'v1'}}, {'k2': {'const': 'v1'}}]
-</code></pre>
-<p>Initialise an empty registry.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class MessageTemplateRegistry:
-    &#34;&#34;&#34;Manage a collection of message templates with registered clients.
-
-    A new MessageTemplateRegistry is created by:
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-
-    Client names (strings) can be registered for message templates, which
-    are mappings from keys to JSON schemas:
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-
-    The check function checks if the templates registered for a client
-    match a given message:
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 1&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-
-    Clients can be registered for values validating against arbitrary JSON
-    schemas, e.g. all values of a certain type:
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;C 2&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 2&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;C 3&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 3&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True
-
-    The order of key-value pairs does not have to match the order in the
-    messages and keys can be left out:
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;C 4&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 4&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True
-
-    A registration for an empty template matches all messages:
-    &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 5&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: True
-
-    A client can be registered for multiple templates:
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 6&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 6&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-
-    Clients can be deregistered again (the result is False if the registry
-    is empty after the deletion):
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 7&#39;)
-    &gt;&gt;&gt; r.delete(&#39;C 7&#39;)
-    True
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.check(&#39;C 7&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: False
-
-    The get function returns all clients with registered templates matching
-    a given message:
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}]:
-    ...     print(f&#34;{m}: {r.get(m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;]
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 1&#39;, &#39;C 6&#39;, &#39;C 4&#39;]
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;C 5&#39;, &#39;C 2&#39;, &#39;C 6&#39;]
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: 2}: [&#39;C 5&#39;, &#39;C 3&#39;, &#39;C 4&#39;]
-
-    The get_templates function returns all templates for a given client:
-    &gt;&gt;&gt; for c in [&#39;C 1&#39;, &#39;C 2&#39;, &#39;C 3&#39;, &#39;C 4&#39;, &#39;C 5&#39;, &#39;C 6&#39;]:
-    ...     print(f&#34;{c}: {r.get_templates(c)}&#34;)
-    C 1: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-    C 2: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]
-    C 3: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]
-    C 4: [{&#39;k2&#39;: {&#39;const&#39;: 2}}]
-    C 5: [{}]
-    C 6: [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-    &#34;&#34;&#34;
-
-    def __init__(self) -&gt; None:
-        &#34;&#34;&#34;Initialise an empty registry.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &#34;&#34;&#34;
-        self._clients: List[str] = []
-        self._children: Dict[str, Dict[str, MessageTemplateRegistry]] = {}
-
-    def insert(self, template: MessageTemplate, client: str) -&gt; None:
-        &#34;&#34;&#34;Register a client for a template.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 2&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)
-        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-
-        Implementation details:
-        -----------------------
-        The tree nodes on the way to a registered object are used/created
-        in the order given in the message template, which can be used to
-        design more efficient lookups (e.g., putting rarer key-value pairs
-        earlier in the template).
-        &gt;&gt;&gt; r._clients
-        [&#39;C 5&#39;]
-        &gt;&gt;&gt; r._children.keys()
-        dict_keys([&#39;k1&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._clients
-        []
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children.keys()
-        dict_keys([&#39;k2&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children[&#39;k2&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-        [&#39;C 1&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-        [&#39;C 2&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._clients
-        []
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._children.keys()
-        dict_keys([&#39;k2&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._children[&#39;k2&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-        [&#39;C 3&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-        [&#39;C 4&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &#34;&#34;&#34;
-        if not template:
-            self._clients.append(client)
-        else:
-            key, schema = next(iter(template.items()))
-            schema_string = json.dumps(schema)
-            reduced_template = MessageTemplate({k: template[k]
-                                                for k in template
-                                                if k != key})
-            if key not in self._children:
-                self._children[key] = {}
-            if schema_string not in self._children[key]:
-                self._children[key][schema_string] = MessageTemplateRegistry()
-            self._children[key][schema_string].insert(reduced_template, client)
-
-    def delete(self, client: str) -&gt; bool:
-        &#34;&#34;&#34;Unregister a client from all templates.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 2&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)
-        &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-        &gt;&gt;&gt; r.delete(&#39;C 3&#39;)
-        True
-        &gt;&gt;&gt; r.delete(&#39;C 4&#39;)
-        True
-
-        Implementation details:
-        -----------------------
-        If parts of the tree become superfluous by the deletion of the
-        client, they are also completely removed to reduce the lookup
-        effort and keep the tree clean.
-        &gt;&gt;&gt; r._clients
-        [&#39;C 5&#39;]
-        &gt;&gt;&gt; r._children.keys()
-        dict_keys([&#39;k1&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._clients
-        []
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children.keys()
-        dict_keys([&#39;k2&#39;])
-        &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children[&#39;k2&#39;].keys()
-        dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-        [&#39;C 1&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-        [&#39;C 2&#39;]
-        &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-        ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-        dict_keys([])
-        &#34;&#34;&#34;
-        self._clients = [c for c in self._clients if c != client]
-        new_children: Dict[str, Dict[str, MessageTemplateRegistry]] = {}
-        for key in self._children:
-            new_children[key] = {}
-            for schema in self._children[key]:
-                if self._children[key][schema].delete(client):
-                    new_children[key][schema] = self._children[key][schema]
-            if not new_children[key]:
-                del new_children[key]
-        self._children = new_children
-        if self._clients or self._children:
-            return True
-        return False
-
-    def check(self, client: str, message: Message) -&gt; bool:
-        &#34;&#34;&#34;Get if a client has a registered template matching a message.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-        ...     print(f&#34;{m}: {r.check(&#39;Client 1&#39;, m)}&#34;)
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: False
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;Client 2&#39;)
-        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-        ...     print(f&#34;{m}: {r.check(&#39;Client 2&#39;, m)}&#34;)
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-        &#34;&#34;&#34;
-        if client in self._clients:
-            return True
-        for key in self._children:
-            if key in message:
-                for schema_string in self._children[key]:
-                    schema = json.loads(schema_string)
-                    validator = jsonschema.Draft7Validator(schema)
-                    validated = True
-                    for error in validator.iter_errors(message[key]):
-                        validated = False
-                    if validated:
-                        child = self._children[key][schema_string]
-                        if child.check(client, message):
-                            return True
-        return False
-
-    def get(self, message: Message) -&gt; List[str]:
-        &#34;&#34;&#34;Get all clients registered for templates matching a message.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;Client 2&#39;)
-        &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-        ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-        ...     print(f&#34;{m}: {r.get(m)}&#34;)
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]
-        {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: [&#39;Client 1&#39;, &#39;Client 2&#39;]
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []
-        {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: [&#39;Client 2&#39;]
-        &#34;&#34;&#34;
-        result = []
-        for client in self._clients:
-            if client not in result:
-                result.append(client)
-        for key in self._children:
-            if key in message:
-                for schema_string in self._children[key]:
-                    schema = json.loads(schema_string)
-                    validator = jsonschema.Draft7Validator(schema)
-                    validated = True
-                    for error in validator.iter_errors(message[key]):
-                        validated = False
-                    if validated:
-                        child = self._children[key][schema_string]
-                        for client in child.get(message):
-                            if client not in result:
-                                result.append(client)
-        return result
-
-    def get_templates(self, client: str) -&gt; List[MessageTemplate]:
-        &#34;&#34;&#34;Get all templates for a client.
-
-        &gt;&gt;&gt; r = MessageTemplateRegistry()
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 1&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},
-        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;Client 2&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 2&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},
-        ...           &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 3&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 3&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;Client 4&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 4&#39;)
-        [{&#39;k2&#39;: {&#39;const&#39;: 2}}]
-        &gt;&gt;&gt; r.insert({}, &#39;Client 5&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 5&#39;)
-        [{}]
-        &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)
-        &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)
-        &gt;&gt;&gt; r.get_templates(&#39;Client 6&#39;)
-        [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-        &#34;&#34;&#34;
-        result = []
-        if client in self._clients:
-            result.append(MessageTemplate())
-        for key in self._children:
-            for schema_string in self._children[key]:
-                schema = json.loads(schema_string)
-                child = self._children[key][schema_string]
-                for template in child.get_templates(client):
-                    current = MessageTemplate({key: schema})
-                    current.update(template)
-                    result.append(current)
-        return result</code></pre>
-</details>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi.messagebus.MessageTemplateRegistry.insert"><code class="name flex">
-<span>def <span class="ident">insert</span></span>(<span>self, template: <a title="controlpi.messagebus.MessageTemplate" href="#controlpi.messagebus.MessageTemplate">MessageTemplate</a>, client: str) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register a client for a template.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}, 'k2': {'const': 'v1'}}, 'C 1')
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}, 'k2': {'const': 'v2'}}, 'C 2')
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'}, 'k2': {'const': 'v1'}}, 'C 3')
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'}, 'k2': {'const': 'v2'}}, 'C 4')
-&gt;&gt;&gt; r.insert({}, 'C 5')
-</code></pre>
-<h2 id="implementation-details">Implementation details:</h2>
-<p>The tree nodes on the way to a registered object are used/created
-in the order given in the message template, which can be used to
-design more efficient lookups (e.g., putting rarer key-value pairs
-earlier in the template).</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r._clients
-['C 5']
-&gt;&gt;&gt; r._children.keys()
-dict_keys(['k1'])
-&gt;&gt;&gt; r._children['k1'].keys()
-dict_keys(['{&quot;const&quot;: &quot;v1&quot;}', '{&quot;const&quot;: &quot;v2&quot;}'])
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']._clients
-[]
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']._children.keys()
-dict_keys(['k2'])
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']._children['k2'].keys()
-dict_keys(['{&quot;const&quot;: &quot;v1&quot;}', '{&quot;const&quot;: &quot;v2&quot;}'])
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v1&quot;}'])._clients
-['C 1']
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v1&quot;}'])._children.keys()
-dict_keys([])
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v2&quot;}'])._clients
-['C 2']
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v2&quot;}'])._children.keys()
-dict_keys([])
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']._clients
-[]
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']._children.keys()
-dict_keys(['k2'])
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']._children['k2'].keys()
-dict_keys(['{&quot;const&quot;: &quot;v1&quot;}', '{&quot;const&quot;: &quot;v2&quot;}'])
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v1&quot;}'])._clients
-['C 3']
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v1&quot;}'])._children.keys()
-dict_keys([])
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v2&quot;}'])._clients
-['C 4']
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v2&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v2&quot;}'])._children.keys()
-dict_keys([])
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def insert(self, template: MessageTemplate, client: str) -&gt; None:
-    &#34;&#34;&#34;Register a client for a template.
-
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 2&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)
-    &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-
-    Implementation details:
-    -----------------------
-    The tree nodes on the way to a registered object are used/created
-    in the order given in the message template, which can be used to
-    design more efficient lookups (e.g., putting rarer key-value pairs
-    earlier in the template).
-    &gt;&gt;&gt; r._clients
-    [&#39;C 5&#39;]
-    &gt;&gt;&gt; r._children.keys()
-    dict_keys([&#39;k1&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;].keys()
-    dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._clients
-    []
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children.keys()
-    dict_keys([&#39;k2&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children[&#39;k2&#39;].keys()
-    dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-    [&#39;C 1&#39;]
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-    dict_keys([])
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-    [&#39;C 2&#39;]
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-    dict_keys([])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._clients
-    []
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._children.keys()
-    dict_keys([&#39;k2&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]._children[&#39;k2&#39;].keys()
-    dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-    [&#39;C 3&#39;]
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-    dict_keys([])
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-    [&#39;C 4&#39;]
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-    dict_keys([])
-    &#34;&#34;&#34;
-    if not template:
-        self._clients.append(client)
-    else:
-        key, schema = next(iter(template.items()))
-        schema_string = json.dumps(schema)
-        reduced_template = MessageTemplate({k: template[k]
-                                            for k in template
-                                            if k != key})
-        if key not in self._children:
-            self._children[key] = {}
-        if schema_string not in self._children[key]:
-            self._children[key][schema_string] = MessageTemplateRegistry()
-        self._children[key][schema_string].insert(reduced_template, client)</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplateRegistry.delete"><code class="name flex">
-<span>def <span class="ident">delete</span></span>(<span>self, client: str) ‑> bool</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Unregister a client from all templates.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}, 'k2': {'const': 'v1'}}, 'C 1')
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}, 'k2': {'const': 'v2'}}, 'C 2')
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'}, 'k2': {'const': 'v1'}}, 'C 3')
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'}, 'k2': {'const': 'v2'}}, 'C 4')
-&gt;&gt;&gt; r.insert({}, 'C 5')
-&gt;&gt;&gt; r.delete('C 3')
-True
-&gt;&gt;&gt; r.delete('C 4')
-True
-</code></pre>
-<h2 id="implementation-details">Implementation details:</h2>
-<p>If parts of the tree become superfluous by the deletion of the
-client, they are also completely removed to reduce the lookup
-effort and keep the tree clean.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r._clients
-['C 5']
-&gt;&gt;&gt; r._children.keys()
-dict_keys(['k1'])
-&gt;&gt;&gt; r._children['k1'].keys()
-dict_keys(['{&quot;const&quot;: &quot;v1&quot;}'])
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']._clients
-[]
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']._children.keys()
-dict_keys(['k2'])
-&gt;&gt;&gt; r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']._children['k2'].keys()
-dict_keys(['{&quot;const&quot;: &quot;v1&quot;}', '{&quot;const&quot;: &quot;v2&quot;}'])
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v1&quot;}'])._clients
-['C 1']
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v1&quot;}'])._children.keys()
-dict_keys([])
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v2&quot;}'])._clients
-['C 2']
-&gt;&gt;&gt; (r._children['k1']['{&quot;const&quot;: &quot;v1&quot;}']
-...   ._children['k2']['{&quot;const&quot;: &quot;v2&quot;}'])._children.keys()
-dict_keys([])
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def delete(self, client: str) -&gt; bool:
-    &#34;&#34;&#34;Unregister a client from all templates.
-
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 1&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 2&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;C 3&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;C 4&#39;)
-    &gt;&gt;&gt; r.insert({}, &#39;C 5&#39;)
-    &gt;&gt;&gt; r.delete(&#39;C 3&#39;)
-    True
-    &gt;&gt;&gt; r.delete(&#39;C 4&#39;)
-    True
-
-    Implementation details:
-    -----------------------
-    If parts of the tree become superfluous by the deletion of the
-    client, they are also completely removed to reduce the lookup
-    effort and keep the tree clean.
-    &gt;&gt;&gt; r._clients
-    [&#39;C 5&#39;]
-    &gt;&gt;&gt; r._children.keys()
-    dict_keys([&#39;k1&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;].keys()
-    dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._clients
-    []
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children.keys()
-    dict_keys([&#39;k2&#39;])
-    &gt;&gt;&gt; r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]._children[&#39;k2&#39;].keys()
-    dict_keys([&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;, &#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._clients
-    [&#39;C 1&#39;]
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;])._children.keys()
-    dict_keys([])
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._clients
-    [&#39;C 2&#39;]
-    &gt;&gt;&gt; (r._children[&#39;k1&#39;][&#39;{&#34;const&#34;: &#34;v1&#34;}&#39;]
-    ...   ._children[&#39;k2&#39;][&#39;{&#34;const&#34;: &#34;v2&#34;}&#39;])._children.keys()
-    dict_keys([])
-    &#34;&#34;&#34;
-    self._clients = [c for c in self._clients if c != client]
-    new_children: Dict[str, Dict[str, MessageTemplateRegistry]] = {}
-    for key in self._children:
-        new_children[key] = {}
-        for schema in self._children[key]:
-            if self._children[key][schema].delete(client):
-                new_children[key][schema] = self._children[key][schema]
-        if not new_children[key]:
-            del new_children[key]
-    self._children = new_children
-    if self._clients or self._children:
-        return True
-    return False</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplateRegistry.check"><code class="name flex">
-<span>def <span class="ident">check</span></span>(<span>self, client: str, message: <a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a>) ‑> bool</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Get if a client has a registered template matching a message.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'Client 1')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 'v2'},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 'v2'}]:
-...     print(f&quot;{m}: {r.check('Client 1', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: True
-{'k1': 'v1', 'k2': 'v2'}: True
-{'k1': 'v2', 'k2': 'v1'}: False
-{'k1': 'v2', 'k2': 'v2'}: False
-&gt;&gt;&gt; r.insert({'k2': {'const': 'v2'}}, 'Client 2')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 'v2'},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 'v2'}]:
-...     print(f&quot;{m}: {r.check('Client 2', m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: False
-{'k1': 'v1', 'k2': 'v2'}: True
-{'k1': 'v2', 'k2': 'v1'}: False
-{'k1': 'v2', 'k2': 'v2'}: True
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def check(self, client: str, message: Message) -&gt; bool:
-    &#34;&#34;&#34;Get if a client has a registered template matching a message.
-
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-    ...     print(f&#34;{m}: {r.check(&#39;Client 1&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: True
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: False
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;Client 2&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-    ...     print(f&#34;{m}: {r.check(&#39;Client 2&#39;, m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: False
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: True
-    &#34;&#34;&#34;
-    if client in self._clients:
-        return True
-    for key in self._children:
-        if key in message:
-            for schema_string in self._children[key]:
-                schema = json.loads(schema_string)
-                validator = jsonschema.Draft7Validator(schema)
-                validated = True
-                for error in validator.iter_errors(message[key]):
-                    validated = False
-                if validated:
-                    child = self._children[key][schema_string]
-                    if child.check(client, message):
-                        return True
-    return False</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplateRegistry.get"><code class="name flex">
-<span>def <span class="ident">get</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a>) ‑> List[str]</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Get all clients registered for templates matching a message.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'Client 1')
-&gt;&gt;&gt; r.insert({'k2': {'const': 'v2'}}, 'Client 2')
-&gt;&gt;&gt; for m in [{'k1': 'v1', 'k2': 'v1'}, {'k1': 'v1', 'k2': 'v2'},
-...           {'k1': 'v2', 'k2': 'v1'}, {'k1': 'v2', 'k2': 'v2'}]:
-...     print(f&quot;{m}: {r.get(m)}&quot;)
-{'k1': 'v1', 'k2': 'v1'}: ['Client 1']
-{'k1': 'v1', 'k2': 'v2'}: ['Client 1', 'Client 2']
-{'k1': 'v2', 'k2': 'v1'}: []
-{'k1': 'v2', 'k2': 'v2'}: ['Client 2']
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def get(self, message: Message) -&gt; List[str]:
-    &#34;&#34;&#34;Get all clients registered for templates matching a message.
-
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v2&#39;}}, &#39;Client 2&#39;)
-    &gt;&gt;&gt; for m in [{&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;},
-    ...           {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}, {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}]:
-    ...     print(f&#34;{m}: {r.get(m)}&#34;)
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v1&#39;}: [&#39;Client 1&#39;]
-    {&#39;k1&#39;: &#39;v1&#39;, &#39;k2&#39;: &#39;v2&#39;}: [&#39;Client 1&#39;, &#39;Client 2&#39;]
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v1&#39;}: []
-    {&#39;k1&#39;: &#39;v2&#39;, &#39;k2&#39;: &#39;v2&#39;}: [&#39;Client 2&#39;]
-    &#34;&#34;&#34;
-    result = []
-    for client in self._clients:
-        if client not in result:
-            result.append(client)
-    for key in self._children:
-        if key in message:
-            for schema_string in self._children[key]:
-                schema = json.loads(schema_string)
-                validator = jsonschema.Draft7Validator(schema)
-                validated = True
-                for error in validator.iter_errors(message[key]):
-                    validated = False
-                if validated:
-                    child = self._children[key][schema_string]
-                    for client in child.get(message):
-                        if client not in result:
-                            result.append(client)
-    return result</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageTemplateRegistry.get_templates"><code class="name flex">
-<span>def <span class="ident">get_templates</span></span>(<span>self, client: str) ‑> List[<a title="controlpi.messagebus.MessageTemplate" href="#controlpi.messagebus.MessageTemplate">MessageTemplate</a>]</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Get all templates for a client.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; r = MessageTemplateRegistry()
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'Client 1')
-&gt;&gt;&gt; r.get_templates('Client 1')
-[{'k1': {'const': 'v1'}}]
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'},
-...           'k2': {'type': 'string'}}, 'Client 2')
-&gt;&gt;&gt; r.get_templates('Client 2')
-[{'k1': {'const': 'v2'}, 'k2': {'type': 'string'}}]
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v2'},
-...           'k2': {'type': 'integer'}}, 'Client 3')
-&gt;&gt;&gt; r.get_templates('Client 3')
-[{'k1': {'const': 'v2'}, 'k2': {'type': 'integer'}}]
-&gt;&gt;&gt; r.insert({'k2': {'const': 2}}, 'Client 4')
-&gt;&gt;&gt; r.get_templates('Client 4')
-[{'k2': {'const': 2}}]
-&gt;&gt;&gt; r.insert({}, 'Client 5')
-&gt;&gt;&gt; r.get_templates('Client 5')
-[{}]
-&gt;&gt;&gt; r.insert({'k1': {'const': 'v1'}}, 'Client 6')
-&gt;&gt;&gt; r.insert({'k2': {'const': 'v1'}}, 'Client 6')
-&gt;&gt;&gt; r.get_templates('Client 6')
-[{'k1': {'const': 'v1'}}, {'k2': {'const': 'v1'}}]
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def get_templates(self, client: str) -&gt; List[MessageTemplate]:
-    &#34;&#34;&#34;Get all templates for a client.
-
-    &gt;&gt;&gt; r = MessageTemplateRegistry()
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 1&#39;)
-    &gt;&gt;&gt; r.get_templates(&#39;Client 1&#39;)
-    [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},
-    ...           &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}, &#39;Client 2&#39;)
-    &gt;&gt;&gt; r.get_templates(&#39;Client 2&#39;)
-    [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;string&#39;}}]
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;},
-    ...           &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}, &#39;Client 3&#39;)
-    &gt;&gt;&gt; r.get_templates(&#39;Client 3&#39;)
-    [{&#39;k1&#39;: {&#39;const&#39;: &#39;v2&#39;}, &#39;k2&#39;: {&#39;type&#39;: &#39;integer&#39;}}]
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: 2}}, &#39;Client 4&#39;)
-    &gt;&gt;&gt; r.get_templates(&#39;Client 4&#39;)
-    [{&#39;k2&#39;: {&#39;const&#39;: 2}}]
-    &gt;&gt;&gt; r.insert({}, &#39;Client 5&#39;)
-    &gt;&gt;&gt; r.get_templates(&#39;Client 5&#39;)
-    [{}]
-    &gt;&gt;&gt; r.insert({&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)
-    &gt;&gt;&gt; r.insert({&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}, &#39;Client 6&#39;)
-    &gt;&gt;&gt; r.get_templates(&#39;Client 6&#39;)
-    [{&#39;k1&#39;: {&#39;const&#39;: &#39;v1&#39;}}, {&#39;k2&#39;: {&#39;const&#39;: &#39;v1&#39;}}]
-    &#34;&#34;&#34;
-    result = []
-    if client in self._clients:
-        result.append(MessageTemplate())
-    for key in self._children:
-        for schema_string in self._children[key]:
-            schema = json.loads(schema_string)
-            child = self._children[key][schema_string]
-            for template in child.get_templates(client):
-                current = MessageTemplate({key: schema})
-                current.update(template)
-                result.append(current)
-    return result</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi.messagebus.BusException"><code class="flex name class">
-<span>class <span class="ident">BusException</span></span>
-<span>(</span><span>*args, **kwargs)</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Raise for errors in using message bus.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class BusException(Exception):
-    &#34;&#34;&#34;Raise for errors in using message bus.&#34;&#34;&#34;</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li>builtins.Exception</li>
-<li>builtins.BaseException</li>
-</ul>
-</dd>
-<dt id="controlpi.messagebus.MessageBus"><code class="flex name class">
-<span>class <span class="ident">MessageBus</span></span>
-</code></dt>
-<dd>
-<div class="desc"><p>Provide an asynchronous message bus.</p>
-<p>The bus executes asynchronous callbacks for all messages to be received
-by a client. We use a simple callback printing the message in all
-examples:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; def callback_for_receiver(receiver):
-...     print(f&quot;Creating callback for {receiver}.&quot;)
-...     async def callback(message):
-...         print(f&quot;{receiver}: {message}&quot;)
-...     return callback
-</code></pre>
-<p>Clients can be registered at the bus with a name, lists of message
-templates they want to use for sending and receiving and a callback
-function for receiving. An empty list of templates means that the
-client does not want to send or receive any messages, respectively.
-A list with an empty template means that it wants to send arbitrary
-or receive all messages, respectively:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def setup(bus):
-...     print(&quot;Setting up.&quot;)
-...     bus.register('Logger', 'Test Plugin',
-...                  [],
-...                  [{}],
-...                  callback_for_receiver('Logger'))
-...     bus.register('Client 1', 'Test Plugin',
-...                  [{'k1': {'type': 'string'}}],
-...                  [{'target': {'const': 'Client 1'}}],
-...                  callback_for_receiver('Client 1'))
-...     bus.register('Client 2', 'Test Plugin',
-...                  [{}],
-...                  [{'target': {'const': 'Client 2'}}],
-...                  callback_for_receiver('Client 2'))
-</code></pre>
-<p>The bus itself is addressed by the empty string. It sends messages for
-each registration and deregestration of a client with a key 'event' and
-a value of 'registered' or 'unregistered', a key 'client' with the
-client's name as value and for registrations also keys 'sends' and
-'receives' with all templates registered for the client for sending and
-receiving.</p>
-<p>Clients can send to the bus with the send function. Each message has to
-declare a sender. The send templates of that sender are checked for a
-template matching the message. We cannot prevent arbitrary code from
-impersonating any sender, but this should only be done in debugging or
-management situations.</p>
-<p>Messages that are intended for a specific client by convention have a
-key 'target' with the target client's name as value. Such messages are
-often commands to the client to do something, which is by convention
-indicated by a key 'command' with a value that indicates what should be
-done.</p>
-<p>The bus, for example, reacts to a message with 'target': '' and
-'command': 'get clients' by sending one message for each currently
-registered with complete information about its registered send and
-receive templates.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def send(bus):
-...     print(&quot;Sending messages.&quot;)
-...     await bus.send({'sender': 'Client 1', 'k1': 'Test'})
-...     await bus.send({'sender': 'Client 2', 'target': 'Client 1'})
-...     await bus.send({'sender': '', 'target': '',
-...                     'command': 'get clients'})
-</code></pre>
-<p>The run function executes the message bus forever. If we want to stop
-it, we have to explicitly cancel the task:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     await setup(bus)
-...     bus_task = asyncio.create_task(bus.run())
-...     await send(bus)
-...     await asyncio.sleep(0)
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-Setting up.
-Creating callback for Logger.
-Creating callback for Client 1.
-Creating callback for Client 2.
-Sending messages.
-Logger: {'sender': '', 'event': 'registered',
-         'client': 'Logger', 'plugin': 'Test Plugin',
-         'sends': [], 'receives': [{}]}
-Logger: {'sender': '', 'event': 'registered',
-         'client': 'Client 1', 'plugin': 'Test Plugin',
-         'sends': [{'k1': {'type': 'string'}}],
-         'receives': [{'target': {'const': 'Client 1'}}]}
-Logger: {'sender': '', 'event': 'registered',
-         'client': 'Client 2', 'plugin': 'Test Plugin',
-         'sends': [{}], 'receives': [{'target': {'const': 'Client 2'}}]}
-Logger: {'sender': 'Client 1', 'k1': 'Test'}
-Logger: {'sender': 'Client 2', 'target': 'Client 1'}
-Client 1: {'sender': 'Client 2', 'target': 'Client 1'}
-Logger: {'sender': '', 'target': '', 'command': 'get clients'}
-Logger: {'sender': '', 'client': 'Logger', 'plugin': 'Test Plugin',
-         'sends': [], 'receives': [{}]}
-Logger: {'sender': '', 'client': 'Client 1', 'plugin': 'Test Plugin',
-         'sends': [{'k1': {'type': 'string'}}],
-         'receives': [{'target': {'const': 'Client 1'}}]}
-Logger: {'sender': '', 'client': 'Client 2', 'plugin': 'Test Plugin',
-         'sends': [{}], 'receives': [{'target': {'const': 'Client 2'}}]}
-</code></pre>
-<p>Initialise a new bus without clients.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-&gt;&gt;&gt; asyncio.run(main())
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class MessageBus:
-    &#34;&#34;&#34;Provide an asynchronous message bus.
-
-    The bus executes asynchronous callbacks for all messages to be received
-    by a client. We use a simple callback printing the message in all
-    examples:
-    &gt;&gt;&gt; def callback_for_receiver(receiver):
-    ...     print(f&#34;Creating callback for {receiver}.&#34;)
-    ...     async def callback(message):
-    ...         print(f&#34;{receiver}: {message}&#34;)
-    ...     return callback
-
-    Clients can be registered at the bus with a name, lists of message
-    templates they want to use for sending and receiving and a callback
-    function for receiving. An empty list of templates means that the
-    client does not want to send or receive any messages, respectively.
-    A list with an empty template means that it wants to send arbitrary
-    or receive all messages, respectively:
-    &gt;&gt;&gt; async def setup(bus):
-    ...     print(&#34;Setting up.&#34;)
-    ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,
-    ...                  [],
-    ...                  [{}],
-    ...                  callback_for_receiver(&#39;Logger&#39;))
-    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-    ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-    ...                  callback_for_receiver(&#39;Client 1&#39;))
-    ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-    ...                  [{}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-    ...                  callback_for_receiver(&#39;Client 2&#39;))
-
-    The bus itself is addressed by the empty string. It sends messages for
-    each registration and deregestration of a client with a key &#39;event&#39; and
-    a value of &#39;registered&#39; or &#39;unregistered&#39;, a key &#39;client&#39; with the
-    client&#39;s name as value and for registrations also keys &#39;sends&#39; and
-    &#39;receives&#39; with all templates registered for the client for sending and
-    receiving.
-
-    Clients can send to the bus with the send function. Each message has to
-    declare a sender. The send templates of that sender are checked for a
-    template matching the message. We cannot prevent arbitrary code from
-    impersonating any sender, but this should only be done in debugging or
-    management situations.
-
-    Messages that are intended for a specific client by convention have a
-    key &#39;target&#39; with the target client&#39;s name as value. Such messages are
-    often commands to the client to do something, which is by convention
-    indicated by a key &#39;command&#39; with a value that indicates what should be
-    done.
-
-    The bus, for example, reacts to a message with &#39;target&#39;: &#39;&#39; and
-    &#39;command&#39;: &#39;get clients&#39; by sending one message for each currently
-    registered with complete information about its registered send and
-    receive templates.
-
-    &gt;&gt;&gt; async def send(bus):
-    ...     print(&#34;Sending messages.&#34;)
-    ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;})
-    ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})
-    ...     await bus.send({&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;,
-    ...                     &#39;command&#39;: &#39;get clients&#39;})
-
-    The run function executes the message bus forever. If we want to stop
-    it, we have to explicitly cancel the task:
-    &gt;&gt;&gt; async def main():
-    ...     bus = MessageBus()
-    ...     await setup(bus)
-    ...     bus_task = asyncio.create_task(bus.run())
-    ...     await send(bus)
-    ...     await asyncio.sleep(0)
-    ...     bus_task.cancel()
-    &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-    Setting up.
-    Creating callback for Logger.
-    Creating callback for Client 1.
-    Creating callback for Client 2.
-    Sending messages.
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}
-    Logger: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;k1&#39;: &#39;Test&#39;}
-    Logger: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-    Client 1: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;target&#39;: &#39;&#39;, &#39;command&#39;: &#39;get clients&#39;}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Logger&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [], &#39;receives&#39;: [{}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 1&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}]}
-    Logger: {&#39;sender&#39;: &#39;&#39;, &#39;client&#39;: &#39;Client 2&#39;, &#39;plugin&#39;: &#39;Test Plugin&#39;,
-             &#39;sends&#39;: [{}], &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}]}
-    &#34;&#34;&#34;
-
-    def __init__(self) -&gt; None:
-        &#34;&#34;&#34;Initialise a new bus without clients.
-
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        self._queue: asyncio.Queue = asyncio.Queue()
-        self._plugins: Dict[str, str] = {}
-        self._send_reg: MessageTemplateRegistry = MessageTemplateRegistry()
-        self._recv_reg: MessageTemplateRegistry = MessageTemplateRegistry()
-        self._callbacks: Dict[str, MessageCallback] = {}
-
-    def register(self, client: str, plugin: str,
-                 sends: Iterable[MessageTemplate],
-                 receives: Iterable[MessageTemplate],
-                 callback: MessageCallback) -&gt; None:
-        &#34;&#34;&#34;Register a client at the message bus.
-
-        &gt;&gt;&gt; async def callback(message):
-        ...     print(message)
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,
-        ...                  [],    # send nothing
-        ...                  [{}],  # receive everything
-        ...                  callback)
-        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-        ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-        ...                      # send with key &#39;k1&#39; and string value
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-        ...                      # receive for this client
-        ...                  callback)
-        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-        ...                  [{}],  # send arbitrary
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-        ...                      # receive for this client
-        ...                  callback)
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        if not client:
-            raise BusException(&#34;Client name is not allowed to be empty.&#34;)
-        if client in self._plugins:
-            raise BusException(f&#34;Client &#39;{client}&#39; already registered&#34;
-                               &#34; at message bus.&#34;)
-        event = Message(&#39;&#39;)
-        event[&#39;event&#39;] = &#39;registered&#39;
-        event[&#39;client&#39;] = client
-        self._plugins[client] = plugin
-        event[&#39;plugin&#39;] = plugin
-        for template in sends:
-            self._send_reg.insert(template, client)
-        event[&#39;sends&#39;] = self._send_reg.get_templates(client)
-        for template in receives:
-            self._recv_reg.insert(template, client)
-        event[&#39;receives&#39;] = self._recv_reg.get_templates(client)
-        self._callbacks[client] = callback
-        self._queue.put_nowait(event)
-
-    def unregister(self, client: str) -&gt; None:
-        &#34;&#34;&#34;Unregister a client from the message bus.
-
-        &gt;&gt;&gt; async def callback(message):
-        ...     print(message)
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-        ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-        ...                  callback)
-        ...     bus.unregister(&#39;Client 1&#39;)
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        if client not in self._plugins:
-            return
-        event = Message(&#39;&#39;)
-        event[&#39;event&#39;] = &#39;unregistered&#39;
-        event[&#39;client&#39;] = client
-        del self._plugins[client]
-        self._send_reg.delete(client)
-        self._recv_reg.delete(client)
-        if client in self._callbacks:
-            del self._callbacks[client]
-        self._queue.put_nowait(event)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run the message bus forever.
-
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus_task = asyncio.create_task(bus.run())
-        ...     bus_task.cancel()
-        &gt;&gt;&gt; asyncio.run(main())
-        &#34;&#34;&#34;
-        while True:
-            message = await self._queue.get()
-            if (&#39;target&#39; in message and
-                    message[&#39;target&#39;] == &#39;&#39; and
-                    &#39;command&#39; in message and
-                    message[&#39;command&#39;] == &#39;get clients&#39;):
-                for client in self._plugins:
-                    answer = Message(&#39;&#39;)
-                    answer[&#39;client&#39;] = client
-                    answer[&#39;plugin&#39;] = self._plugins[client]
-                    answer[&#39;sends&#39;] = self._send_reg.get_templates(client)
-                    answer[&#39;receives&#39;] = self._recv_reg.get_templates(client)
-                    await self._queue.put(answer)
-            for client in self._recv_reg.get(message):
-                await self._callbacks[client](message)
-            self._queue.task_done()
-
-    async def send(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Send a message to the message bus.
-
-        &gt;&gt;&gt; async def callback(message):
-        ...     print(f&#34;Got: {message}&#34;)
-        &gt;&gt;&gt; async def main():
-        ...     bus = MessageBus()
-        ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-        ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-        ...                  callback)
-        ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-        ...                  [{}],
-        ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-        ...                  callback)
-        ...     bus_task = asyncio.create_task(bus.run())
-        ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,
-        ...                     &#39;k1&#39;: &#39;Test&#39;})
-        ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})
-        ...     try:
-        ...         await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,
-        ...                         &#39;k1&#39;: 42})
-        ...     except BusException as e:
-        ...         print(e)
-        ...     await asyncio.sleep(0)
-        ...     bus_task.cancel()
-        &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-        Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;
-        not allowed for sender &#39;Client 1&#39;.
-        Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}
-        Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-        &#34;&#34;&#34;
-        assert isinstance(message[&#39;sender&#39;], str)
-        sender = message[&#39;sender&#39;]
-        if sender:
-            if not self._send_reg.check(sender, message):
-                raise BusException(f&#34;Message &#39;{message}&#39; not allowed for&#34;
-                                   f&#34; sender &#39;{sender}&#39;.&#34;)
-        await self._queue.put(message)</code></pre>
-</details>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi.messagebus.MessageBus.register"><code class="name flex">
-<span>def <span class="ident">register</span></span>(<span>self, client: str, plugin: str, sends: Iterable[<a title="controlpi.messagebus.MessageTemplate" href="#controlpi.messagebus.MessageTemplate">MessageTemplate</a>], receives: Iterable[<a title="controlpi.messagebus.MessageTemplate" href="#controlpi.messagebus.MessageTemplate">MessageTemplate</a>], callback: Callable[[ForwardRef('<a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a>')], Coroutine[Any, Any, NoneType]]) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register a client at the message bus.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def callback(message):
-...     print(message)
-&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     bus.register('Logger', 'Test Plugin',
-...                  [],    # send nothing
-...                  [{}],  # receive everything
-...                  callback)
-...     bus.register('Client 1', 'Test Plugin',
-...                  [{'k1': {'type': 'string'}}],
-...                      # send with key 'k1' and string value
-...                  [{'target': {'const': 'Client 1'}}],
-...                      # receive for this client
-...                  callback)
-...     bus.register('Client 2', 'Test Plugin',
-...                  [{}],  # send arbitrary
-...                  [{'target': {'const': 'Client 2'}}],
-...                      # receive for this client
-...                  callback)
-&gt;&gt;&gt; asyncio.run(main())
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def register(self, client: str, plugin: str,
-             sends: Iterable[MessageTemplate],
-             receives: Iterable[MessageTemplate],
-             callback: MessageCallback) -&gt; None:
-    &#34;&#34;&#34;Register a client at the message bus.
-
-    &gt;&gt;&gt; async def callback(message):
-    ...     print(message)
-    &gt;&gt;&gt; async def main():
-    ...     bus = MessageBus()
-    ...     bus.register(&#39;Logger&#39;, &#39;Test Plugin&#39;,
-    ...                  [],    # send nothing
-    ...                  [{}],  # receive everything
-    ...                  callback)
-    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-    ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-    ...                      # send with key &#39;k1&#39; and string value
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-    ...                      # receive for this client
-    ...                  callback)
-    ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-    ...                  [{}],  # send arbitrary
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-    ...                      # receive for this client
-    ...                  callback)
-    &gt;&gt;&gt; asyncio.run(main())
-    &#34;&#34;&#34;
-    if not client:
-        raise BusException(&#34;Client name is not allowed to be empty.&#34;)
-    if client in self._plugins:
-        raise BusException(f&#34;Client &#39;{client}&#39; already registered&#34;
-                           &#34; at message bus.&#34;)
-    event = Message(&#39;&#39;)
-    event[&#39;event&#39;] = &#39;registered&#39;
-    event[&#39;client&#39;] = client
-    self._plugins[client] = plugin
-    event[&#39;plugin&#39;] = plugin
-    for template in sends:
-        self._send_reg.insert(template, client)
-    event[&#39;sends&#39;] = self._send_reg.get_templates(client)
-    for template in receives:
-        self._recv_reg.insert(template, client)
-    event[&#39;receives&#39;] = self._recv_reg.get_templates(client)
-    self._callbacks[client] = callback
-    self._queue.put_nowait(event)</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageBus.unregister"><code class="name flex">
-<span>def <span class="ident">unregister</span></span>(<span>self, client: str) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Unregister a client from the message bus.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def callback(message):
-...     print(message)
-&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     bus.register('Client 1', 'Test Plugin',
-...                  [{'k1': {'type': 'string'}}],
-...                  [{'target': {'const': 'Client 1'}}],
-...                  callback)
-...     bus.unregister('Client 1')
-&gt;&gt;&gt; asyncio.run(main())
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def unregister(self, client: str) -&gt; None:
-    &#34;&#34;&#34;Unregister a client from the message bus.
-
-    &gt;&gt;&gt; async def callback(message):
-    ...     print(message)
-    &gt;&gt;&gt; async def main():
-    ...     bus = MessageBus()
-    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-    ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-    ...                  callback)
-    ...     bus.unregister(&#39;Client 1&#39;)
-    &gt;&gt;&gt; asyncio.run(main())
-    &#34;&#34;&#34;
-    if client not in self._plugins:
-        return
-    event = Message(&#39;&#39;)
-    event[&#39;event&#39;] = &#39;unregistered&#39;
-    event[&#39;client&#39;] = client
-    del self._plugins[client]
-    self._send_reg.delete(client)
-    self._recv_reg.delete(client)
-    if client in self._callbacks:
-        del self._callbacks[client]
-    self._queue.put_nowait(event)</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageBus.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run the message bus forever.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     bus_task = asyncio.create_task(bus.run())
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(main())
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run the message bus forever.
-
-    &gt;&gt;&gt; async def main():
-    ...     bus = MessageBus()
-    ...     bus_task = asyncio.create_task(bus.run())
-    ...     bus_task.cancel()
-    &gt;&gt;&gt; asyncio.run(main())
-    &#34;&#34;&#34;
-    while True:
-        message = await self._queue.get()
-        if (&#39;target&#39; in message and
-                message[&#39;target&#39;] == &#39;&#39; and
-                &#39;command&#39; in message and
-                message[&#39;command&#39;] == &#39;get clients&#39;):
-            for client in self._plugins:
-                answer = Message(&#39;&#39;)
-                answer[&#39;client&#39;] = client
-                answer[&#39;plugin&#39;] = self._plugins[client]
-                answer[&#39;sends&#39;] = self._send_reg.get_templates(client)
-                answer[&#39;receives&#39;] = self._recv_reg.get_templates(client)
-                await self._queue.put(answer)
-        for client in self._recv_reg.get(message):
-            await self._callbacks[client](message)
-        self._queue.task_done()</code></pre>
-</details>
-</dd>
-<dt id="controlpi.messagebus.MessageBus.send"><code class="name flex">
-<span>async def <span class="ident">send</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Send a message to the message bus.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; async def callback(message):
-...     print(f&quot;Got: {message}&quot;)
-&gt;&gt;&gt; async def main():
-...     bus = MessageBus()
-...     bus.register('Client 1', 'Test Plugin',
-...                  [{'k1': {'type': 'string'}}],
-...                  [{'target': {'const': 'Client 1'}}],
-...                  callback)
-...     bus.register('Client 2', 'Test Plugin',
-...                  [{}],
-...                  [{'target': {'const': 'Client 2'}}],
-...                  callback)
-...     bus_task = asyncio.create_task(bus.run())
-...     await bus.send({'sender': 'Client 1', 'target': 'Client 2',
-...                     'k1': 'Test'})
-...     await bus.send({'sender': 'Client 2', 'target': 'Client 1'})
-...     try:
-...         await bus.send({'sender': 'Client 1', 'target': 'Client 2',
-...                         'k1': 42})
-...     except BusException as e:
-...         print(e)
-...     await asyncio.sleep(0)
-...     bus_task.cancel()
-&gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-Message '{'sender': 'Client 1', 'target': 'Client 2', 'k1': 42}'
-not allowed for sender 'Client 1'.
-Got: {'sender': 'Client 1', 'target': 'Client 2', 'k1': 'Test'}
-Got: {'sender': 'Client 2', 'target': 'Client 1'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def send(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Send a message to the message bus.
-
-    &gt;&gt;&gt; async def callback(message):
-    ...     print(f&#34;Got: {message}&#34;)
-    &gt;&gt;&gt; async def main():
-    ...     bus = MessageBus()
-    ...     bus.register(&#39;Client 1&#39;, &#39;Test Plugin&#39;,
-    ...                  [{&#39;k1&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 1&#39;}}],
-    ...                  callback)
-    ...     bus.register(&#39;Client 2&#39;, &#39;Test Plugin&#39;,
-    ...                  [{}],
-    ...                  [{&#39;target&#39;: {&#39;const&#39;: &#39;Client 2&#39;}}],
-    ...                  callback)
-    ...     bus_task = asyncio.create_task(bus.run())
-    ...     await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,
-    ...                     &#39;k1&#39;: &#39;Test&#39;})
-    ...     await bus.send({&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;})
-    ...     try:
-    ...         await bus.send({&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;,
-    ...                         &#39;k1&#39;: 42})
-    ...     except BusException as e:
-    ...         print(e)
-    ...     await asyncio.sleep(0)
-    ...     bus_task.cancel()
-    &gt;&gt;&gt; asyncio.run(main())  # doctest: +NORMALIZE_WHITESPACE
-    Message &#39;{&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: 42}&#39;
-    not allowed for sender &#39;Client 1&#39;.
-    Got: {&#39;sender&#39;: &#39;Client 1&#39;, &#39;target&#39;: &#39;Client 2&#39;, &#39;k1&#39;: &#39;Test&#39;}
-    Got: {&#39;sender&#39;: &#39;Client 2&#39;, &#39;target&#39;: &#39;Client 1&#39;}
-    &#34;&#34;&#34;
-    assert isinstance(message[&#39;sender&#39;], str)
-    sender = message[&#39;sender&#39;]
-    if sender:
-        if not self._send_reg.check(sender, message):
-            raise BusException(f&#34;Message &#39;{message}&#39; not allowed for&#34;
-                               f&#34; sender &#39;{sender}&#39;.&#34;)
-    await self._queue.put(message)</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-</dl>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3>Super-module</h3>
-<ul>
-<li><code><a title="controlpi" href="index.html">controlpi</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-classes">Classes</a></h3>
-<ul>
-<li>
-<h4><code><a title="controlpi.messagebus.Message" href="#controlpi.messagebus.Message">Message</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi.messagebus.Message.check_value" href="#controlpi.messagebus.Message.check_value">check_value</a></code></li>
-<li><code><a title="controlpi.messagebus.Message.update" href="#controlpi.messagebus.Message.update">update</a></code></li>
-<li><code><a title="controlpi.messagebus.Message.setdefault" href="#controlpi.messagebus.Message.setdefault">setdefault</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi.messagebus.MessageTemplate" href="#controlpi.messagebus.MessageTemplate">MessageTemplate</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi.messagebus.MessageTemplate.from_message" href="#controlpi.messagebus.MessageTemplate.from_message">from_message</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplate.update" href="#controlpi.messagebus.MessageTemplate.update">update</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplate.setdefault" href="#controlpi.messagebus.MessageTemplate.setdefault">setdefault</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplate.check" href="#controlpi.messagebus.MessageTemplate.check">check</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi.messagebus.MessageTemplateRegistry" href="#controlpi.messagebus.MessageTemplateRegistry">MessageTemplateRegistry</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi.messagebus.MessageTemplateRegistry.insert" href="#controlpi.messagebus.MessageTemplateRegistry.insert">insert</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplateRegistry.delete" href="#controlpi.messagebus.MessageTemplateRegistry.delete">delete</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplateRegistry.check" href="#controlpi.messagebus.MessageTemplateRegistry.check">check</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplateRegistry.get" href="#controlpi.messagebus.MessageTemplateRegistry.get">get</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageTemplateRegistry.get_templates" href="#controlpi.messagebus.MessageTemplateRegistry.get_templates">get_templates</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi.messagebus.BusException" href="#controlpi.messagebus.BusException">BusException</a></code></h4>
-</li>
-<li>
-<h4><code><a title="controlpi.messagebus.MessageBus" href="#controlpi.messagebus.MessageBus">MessageBus</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi.messagebus.MessageBus.register" href="#controlpi.messagebus.MessageBus.register">register</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageBus.unregister" href="#controlpi.messagebus.MessageBus.unregister">unregister</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageBus.run" href="#controlpi.messagebus.MessageBus.run">run</a></code></li>
-<li><code><a title="controlpi.messagebus.MessageBus.send" href="#controlpi.messagebus.MessageBus.send">send</a></code></li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi/pluginregistry.html b/doc/controlpi/pluginregistry.html
deleted file mode 100644 (file)
index ad9a464..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi.pluginregistry API documentation</title>
-<meta name="description" content="Provide a generic plugin system …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Module <code>controlpi.pluginregistry</code></h1>
-</header>
-<section id="section-intro">
-<p>Provide a generic plugin system.</p>
-<p>The class PluginRegistry is initialised with the name of a namespace
-package and a base class.</p>
-<p>All modules in the namespace package are loaded. These modules can be
-included in different distribution packages, which allows to dynamically
-add plugins to the system without changing any code.</p>
-<p>Afterwards, all (direct and indirect) subclasses of the base class are
-registered as plugins under their class name. Class names should be unique,
-which cannot be programmatically enforced.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class BasePlugin:
-...     pass
-&gt;&gt;&gt; class Plugin1(BasePlugin):
-...     pass
-&gt;&gt;&gt; class Plugin2(BasePlugin):
-...     pass
-&gt;&gt;&gt; registry = PluginRegistry('importlib', BasePlugin)
-</code></pre>
-<p>The registry provides a generic mapping interface with the class names as
-keys and the classes as values.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; print(len(registry))
-2
-&gt;&gt;&gt; for name in registry:
-...     print(f&quot;{name}: {registry[name]}&quot;)
-Plugin1: &lt;class 'pluginregistry.Plugin1'&gt;
-Plugin2: &lt;class 'pluginregistry.Plugin2'&gt;
-&gt;&gt;&gt; if 'Plugin1' in registry:
-...     print(f&quot;'Plugin1' is in registry.&quot;)
-'Plugin1' is in registry.
-&gt;&gt;&gt; p1 = registry['Plugin1']
-&gt;&gt;&gt; i1 = p1()
-</code></pre>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Provide a generic plugin system.
-
-The class PluginRegistry is initialised with the name of a namespace
-package and a base class.
-
-All modules in the namespace package are loaded. These modules can be
-included in different distribution packages, which allows to dynamically
-add plugins to the system without changing any code.
-
-Afterwards, all (direct and indirect) subclasses of the base class are
-registered as plugins under their class name. Class names should be unique,
-which cannot be programmatically enforced.
-
-&gt;&gt;&gt; class BasePlugin:
-...     pass
-&gt;&gt;&gt; class Plugin1(BasePlugin):
-...     pass
-&gt;&gt;&gt; class Plugin2(BasePlugin):
-...     pass
-&gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-
-The registry provides a generic mapping interface with the class names as
-keys and the classes as values.
-
-&gt;&gt;&gt; print(len(registry))
-2
-&gt;&gt;&gt; for name in registry:
-...     print(f&#34;{name}: {registry[name]}&#34;)
-Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-&gt;&gt;&gt; if &#39;Plugin1&#39; in registry:
-...     print(f&#34;&#39;Plugin1&#39; is in registry.&#34;)
-&#39;Plugin1&#39; is in registry.
-&gt;&gt;&gt; p1 = registry[&#39;Plugin1&#39;]
-&gt;&gt;&gt; i1 = p1()
-&#34;&#34;&#34;
-import importlib
-import pkgutil
-import collections.abc
-
-
-class PluginRegistry(collections.abc.Mapping):
-    &#34;&#34;&#34;Provide a registry for plugins.
-
-    Initialise the registry by loading all modules in the given namespace
-    package and then registering all subclasses of the given base class as
-    plugins (only simulated here – the code for Plugin1 and Plugin2 should
-    be in modules in the given namespace package in real applications):
-    &gt;&gt;&gt; class BasePlugin:
-    ...     pass
-    &gt;&gt;&gt; class Plugin1(BasePlugin):
-    ...     pass
-    &gt;&gt;&gt; class Plugin2(BasePlugin):
-    ...     pass
-    &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-
-    After initialisation, provide a mapping interface to the plugins:
-    &gt;&gt;&gt; print(len(registry))
-    2
-    &gt;&gt;&gt; for name in registry:
-    ...     print(f&#34;{name}: {registry[name]}&#34;)
-    Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-    Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-    &gt;&gt;&gt; if &#39;Plugin1&#39; in registry:
-    ...     print(f&#34;&#39;Plugin1&#39; is in registry.&#34;)
-    &#39;Plugin1&#39; is in registry.
-    &#34;&#34;&#34;
-
-    def __init__(self, namespace_package: str, base_class: type) -&gt; None:
-        &#34;&#34;&#34;Initialise registry.
-
-        Import all modules defined in the given namespace package (in any
-        distribution package currently installed in the path). Then register
-        all subclasses of the given base class as plugins.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; for name in registry._plugins:
-        ...     print(f&#34;{name}: {registry._plugins[name]}&#34;)
-        Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-        Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-        &#34;&#34;&#34;
-        ns_mod = importlib.import_module(namespace_package)
-        ns_path = ns_mod.__path__  # type: ignore  # mypy issue #1422
-        ns_name = ns_mod.__name__
-        for _, mod_name, _ in pkgutil.iter_modules(ns_path):
-            importlib.import_module(f&#34;{ns_name}.{mod_name}&#34;)
-
-        def all_subclasses(cls):
-            result = []
-            for subcls in cls.__subclasses__():
-                result.append(subcls)
-                result.extend(all_subclasses(subcls))
-            return result
-        self._plugins = {cls.__name__: cls
-                         for cls in all_subclasses(base_class)}
-
-    def __len__(self) -&gt; int:
-        &#34;&#34;&#34;Get number of registered plugins.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; print(registry.__len__())
-        2
-        &#34;&#34;&#34;
-        return len(self._plugins)
-
-    def __iter__(self):
-        &#34;&#34;&#34;Get an iterator of the registered plugins.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; print(type(registry.__iter__()))
-        &lt;class &#39;dict_keyiterator&#39;&gt;
-        &gt;&gt;&gt; for name in registry:
-        ...     print(name)
-        Plugin1
-        Plugin2
-        &#34;&#34;&#34;
-        return iter(self._plugins)
-
-    def __getitem__(self, plugin_name: str) -&gt; type:
-        &#34;&#34;&#34;Get a registered plugin given its name.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin1&#39;))
-        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin2&#39;))
-        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-        &gt;&gt;&gt; for name in registry:
-        ...     print(registry[name])
-        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-        &#34;&#34;&#34;
-        return self._plugins[plugin_name]</code></pre>
-</details>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-classes">Classes</h2>
-<dl>
-<dt id="controlpi.pluginregistry.PluginRegistry"><code class="flex name class">
-<span>class <span class="ident">PluginRegistry</span></span>
-<span>(</span><span>namespace_package: str, base_class: type)</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Provide a registry for plugins.</p>
-<p>Initialise the registry by loading all modules in the given namespace
-package and then registering all subclasses of the given base class as
-plugins (only simulated here – the code for Plugin1 and Plugin2 should
-be in modules in the given namespace package in real applications):</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class BasePlugin:
-...     pass
-&gt;&gt;&gt; class Plugin1(BasePlugin):
-...     pass
-&gt;&gt;&gt; class Plugin2(BasePlugin):
-...     pass
-&gt;&gt;&gt; registry = PluginRegistry('importlib', BasePlugin)
-</code></pre>
-<p>After initialisation, provide a mapping interface to the plugins:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; print(len(registry))
-2
-&gt;&gt;&gt; for name in registry:
-...     print(f&quot;{name}: {registry[name]}&quot;)
-Plugin1: &lt;class 'pluginregistry.Plugin1'&gt;
-Plugin2: &lt;class 'pluginregistry.Plugin2'&gt;
-&gt;&gt;&gt; if 'Plugin1' in registry:
-...     print(f&quot;'Plugin1' is in registry.&quot;)
-'Plugin1' is in registry.
-</code></pre>
-<p>Initialise registry.</p>
-<p>Import all modules defined in the given namespace package (in any
-distribution package currently installed in the path). Then register
-all subclasses of the given base class as plugins.</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; class BasePlugin:
-...     pass
-&gt;&gt;&gt; class Plugin1(BasePlugin):
-...     pass
-&gt;&gt;&gt; class Plugin2(BasePlugin):
-...     pass
-&gt;&gt;&gt; registry = PluginRegistry('importlib', BasePlugin)
-&gt;&gt;&gt; for name in registry._plugins:
-...     print(f&quot;{name}: {registry._plugins[name]}&quot;)
-Plugin1: &lt;class 'pluginregistry.Plugin1'&gt;
-Plugin2: &lt;class 'pluginregistry.Plugin2'&gt;
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class PluginRegistry(collections.abc.Mapping):
-    &#34;&#34;&#34;Provide a registry for plugins.
-
-    Initialise the registry by loading all modules in the given namespace
-    package and then registering all subclasses of the given base class as
-    plugins (only simulated here – the code for Plugin1 and Plugin2 should
-    be in modules in the given namespace package in real applications):
-    &gt;&gt;&gt; class BasePlugin:
-    ...     pass
-    &gt;&gt;&gt; class Plugin1(BasePlugin):
-    ...     pass
-    &gt;&gt;&gt; class Plugin2(BasePlugin):
-    ...     pass
-    &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-
-    After initialisation, provide a mapping interface to the plugins:
-    &gt;&gt;&gt; print(len(registry))
-    2
-    &gt;&gt;&gt; for name in registry:
-    ...     print(f&#34;{name}: {registry[name]}&#34;)
-    Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-    Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-    &gt;&gt;&gt; if &#39;Plugin1&#39; in registry:
-    ...     print(f&#34;&#39;Plugin1&#39; is in registry.&#34;)
-    &#39;Plugin1&#39; is in registry.
-    &#34;&#34;&#34;
-
-    def __init__(self, namespace_package: str, base_class: type) -&gt; None:
-        &#34;&#34;&#34;Initialise registry.
-
-        Import all modules defined in the given namespace package (in any
-        distribution package currently installed in the path). Then register
-        all subclasses of the given base class as plugins.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; for name in registry._plugins:
-        ...     print(f&#34;{name}: {registry._plugins[name]}&#34;)
-        Plugin1: &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-        Plugin2: &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-        &#34;&#34;&#34;
-        ns_mod = importlib.import_module(namespace_package)
-        ns_path = ns_mod.__path__  # type: ignore  # mypy issue #1422
-        ns_name = ns_mod.__name__
-        for _, mod_name, _ in pkgutil.iter_modules(ns_path):
-            importlib.import_module(f&#34;{ns_name}.{mod_name}&#34;)
-
-        def all_subclasses(cls):
-            result = []
-            for subcls in cls.__subclasses__():
-                result.append(subcls)
-                result.extend(all_subclasses(subcls))
-            return result
-        self._plugins = {cls.__name__: cls
-                         for cls in all_subclasses(base_class)}
-
-    def __len__(self) -&gt; int:
-        &#34;&#34;&#34;Get number of registered plugins.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; print(registry.__len__())
-        2
-        &#34;&#34;&#34;
-        return len(self._plugins)
-
-    def __iter__(self):
-        &#34;&#34;&#34;Get an iterator of the registered plugins.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; print(type(registry.__iter__()))
-        &lt;class &#39;dict_keyiterator&#39;&gt;
-        &gt;&gt;&gt; for name in registry:
-        ...     print(name)
-        Plugin1
-        Plugin2
-        &#34;&#34;&#34;
-        return iter(self._plugins)
-
-    def __getitem__(self, plugin_name: str) -&gt; type:
-        &#34;&#34;&#34;Get a registered plugin given its name.
-
-        &gt;&gt;&gt; class BasePlugin:
-        ...     pass
-        &gt;&gt;&gt; class Plugin1(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; class Plugin2(BasePlugin):
-        ...     pass
-        &gt;&gt;&gt; registry = PluginRegistry(&#39;importlib&#39;, BasePlugin)
-        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin1&#39;))
-        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-        &gt;&gt;&gt; print(registry.__getitem__(&#39;Plugin2&#39;))
-        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-        &gt;&gt;&gt; for name in registry:
-        ...     print(registry[name])
-        &lt;class &#39;pluginregistry.Plugin1&#39;&gt;
-        &lt;class &#39;pluginregistry.Plugin2&#39;&gt;
-        &#34;&#34;&#34;
-        return self._plugins[plugin_name]</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li>collections.abc.Mapping</li>
-<li>collections.abc.Collection</li>
-<li>collections.abc.Sized</li>
-<li>collections.abc.Iterable</li>
-<li>collections.abc.Container</li>
-</ul>
-</dd>
-</dl>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3>Super-module</h3>
-<ul>
-<li><code><a title="controlpi" href="index.html">controlpi</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-classes">Classes</a></h3>
-<ul>
-<li>
-<h4><code><a title="controlpi.pluginregistry.PluginRegistry" href="#controlpi.pluginregistry.PluginRegistry">PluginRegistry</a></code></h4>
-</li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi_plugins/index.html b/doc/controlpi_plugins/index.html
deleted file mode 100644 (file)
index 6775c5d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi_plugins API documentation</title>
-<meta name="description" content="" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Namespace <code>controlpi_plugins</code></h1>
-</header>
-<section id="section-intro">
-</section>
-<section>
-<h2 class="section-title" id="header-submodules">Sub-modules</h2>
-<dl>
-<dt><code class="name"><a title="controlpi_plugins.state" href="state.html">controlpi_plugins.state</a></code></dt>
-<dd>
-<div class="desc"><p>Provide state plugins for all kinds of systems …</p></div>
-</dd>
-<dt><code class="name"><a title="controlpi_plugins.util" href="util.html">controlpi_plugins.util</a></code></dt>
-<dd>
-<div class="desc"><p>Provide utility plugins for all kinds of systems …</p></div>
-</dd>
-<dt><code class="name"><a title="controlpi_plugins.wait" href="wait.html">controlpi_plugins.wait</a></code></dt>
-<dd>
-<div class="desc"><p>Provide waiting/sleeping plugins for all kinds of systems …</p></div>
-</dd>
-</dl>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3><a href="#header-submodules">Sub-modules</a></h3>
-<ul>
-<li><code><a title="controlpi_plugins.state" href="state.html">controlpi_plugins.state</a></code></li>
-<li><code><a title="controlpi_plugins.util" href="util.html">controlpi_plugins.util</a></code></li>
-<li><code><a title="controlpi_plugins.wait" href="wait.html">controlpi_plugins.wait</a></code></li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi_plugins/state.html b/doc/controlpi_plugins/state.html
deleted file mode 100644 (file)
index 8f33480..0000000
+++ /dev/null
@@ -1,1884 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi_plugins.state API documentation</title>
-<meta name="description" content="Provide state plugins for all kinds of systems …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Module <code>controlpi_plugins.state</code></h1>
-</header>
-<section id="section-intro">
-<p>Provide state plugins for all kinds of systems.</p>
-<ul>
-<li>State represents a Boolean state.</li>
-<li>StateAlias translates to another state-like client.</li>
-<li>AndState combines several state-like clients by conjunction.</li>
-<li>OrState combines several state-like clients by disjunction.</li>
-</ul>
-<p>All these plugins use the following conventions:</p>
-<ul>
-<li>If their state changes they send a message containing "event": "changed"
-and "state": <new state>.</li>
-<li>If their state is reported due to a message, but did not change they send
-a message containing just "state": <current state>.</li>
-<li>If they receive a message containing "target": <name> and
-"command": "get state" they report their current state.</li>
-<li>If State (or any other settable state using these conventions) receives
-a message containing "target": <name>, "command": "set state" and
-"new state": <state to be set> it changes the state accordingly. If this
-was really a change the corresponding event is sent. If it was already in
-this state a report message without "event": "changed" is sent.</li>
-<li>StateAlias can alias any message bus client using these conventions, not
-just State instances. It translates all messages described here in both
-directions.</li>
-<li>AndState and OrState instances cannot be set.</li>
-<li>AndState and OrState can combine any message bus clients using these
-conventions, not just State instances. They only react to messages
-containing "state" information.</li>
-</ul>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import asyncio
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test StateAlias&quot;: {&quot;plugin&quot;: &quot;StateAlias&quot;,
-...                          &quot;alias for&quot;: &quot;Test State 2&quot;},
-...      &quot;Test AndState&quot;: {&quot;plugin&quot;: &quot;AndState&quot;,
-...                        &quot;states&quot;: [&quot;Test State&quot;, &quot;Test StateAlias&quot;]},
-...      &quot;Test OrState&quot;: {&quot;plugin&quot;: &quot;OrState&quot;,
-...                       &quot;states&quot;: [&quot;Test State&quot;, &quot;Test StateAlias&quot;]}},
-...     [{&quot;target&quot;: &quot;Test AndState&quot;,
-...       &quot;command&quot;: &quot;get state&quot;},
-...      {&quot;target&quot;: &quot;Test OrState&quot;,
-...       &quot;command&quot;: &quot;get state&quot;},
-...      {&quot;target&quot;: &quot;Test State&quot;,
-...       &quot;command&quot;: &quot;set state&quot;, &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test StateAlias&quot;,
-...       &quot;command&quot;: &quot;set state&quot;, &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State&quot;,
-...       &quot;command&quot;: &quot;set state&quot;, &quot;new state&quot;: False}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State 2', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State 2'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State 2'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test StateAlias', 'plugin': 'StateAlias',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}},
-                   {'target': {'const': 'Test State 2'},
-                    'command': {'const': 'get state'}},
-                   {'target': {'const': 'Test State 2'},
-                    'command': {'const': 'set state'},
-                    'new state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test StateAlias'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test StateAlias'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test State 2'},
-                       'event': {'const': 'changed'},
-                       'state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test State 2'},
-                       'state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test AndState', 'plugin': 'AndState',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test AndState'},
-                       'command': {'const': 'get state'}},
-                      {'sender': {'const': 'Test State'},
-                       'state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test StateAlias'},
-                       'state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test OrState', 'plugin': 'OrState',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test OrState'},
-                       'command': {'const': 'get state'}},
-                      {'sender': {'const': 'Test State'},
-                       'state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test StateAlias'},
-                       'state': {'type': 'boolean'}}]}
-test(): {'sender': 'test()', 'target': 'Test AndState',
-         'command': 'get state'}
-test(): {'sender': 'Test AndState', 'state': False}
-test(): {'sender': 'test()', 'target': 'Test OrState',
-         'command': 'get state'}
-test(): {'sender': 'Test OrState', 'state': False}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State', 'event': 'changed', 'state': True}
-test(): {'sender': 'Test OrState', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test StateAlias',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test StateAlias', 'target': 'Test State 2',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State 2', 'event': 'changed', 'state': True}
-test(): {'sender': 'Test StateAlias', 'event': 'changed', 'state': True}
-test(): {'sender': 'Test AndState', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'set state', 'new state': False}
-test(): {'sender': 'Test State', 'event': 'changed', 'state': False}
-test(): {'sender': 'Test AndState', 'event': 'changed', 'state': False}
-</code></pre>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Provide state plugins for all kinds of systems.
-
-- State represents a Boolean state.
-- StateAlias translates to another state-like client.
-- AndState combines several state-like clients by conjunction.
-- OrState combines several state-like clients by disjunction.
-
-All these plugins use the following conventions:
-
-- If their state changes they send a message containing &#34;event&#34;: &#34;changed&#34;
-  and &#34;state&#34;: &lt;new state&gt;.
-- If their state is reported due to a message, but did not change they send
-  a message containing just &#34;state&#34;: &lt;current state&gt;.
-- If they receive a message containing &#34;target&#34;: &lt;name&gt; and
-  &#34;command&#34;: &#34;get state&#34; they report their current state.
-- If State (or any other settable state using these conventions) receives
-  a message containing &#34;target&#34;: &lt;name&gt;, &#34;command&#34;: &#34;set state&#34; and
-  &#34;new state&#34;: &lt;state to be set&gt; it changes the state accordingly. If this
-  was really a change the corresponding event is sent. If it was already in
-  this state a report message without &#34;event&#34;: &#34;changed&#34; is sent.
-- StateAlias can alias any message bus client using these conventions, not
-  just State instances. It translates all messages described here in both
-  directions.
-- AndState and OrState instances cannot be set.
-- AndState and OrState can combine any message bus clients using these
-  conventions, not just State instances. They only react to messages
-  containing &#34;state&#34; information.
-
-&gt;&gt;&gt; import asyncio
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&#34;Test State&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-...      &#34;Test State 2&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-...      &#34;Test StateAlias&#34;: {&#34;plugin&#34;: &#34;StateAlias&#34;,
-...                          &#34;alias for&#34;: &#34;Test State 2&#34;},
-...      &#34;Test AndState&#34;: {&#34;plugin&#34;: &#34;AndState&#34;,
-...                        &#34;states&#34;: [&#34;Test State&#34;, &#34;Test StateAlias&#34;]},
-...      &#34;Test OrState&#34;: {&#34;plugin&#34;: &#34;OrState&#34;,
-...                       &#34;states&#34;: [&#34;Test State&#34;, &#34;Test StateAlias&#34;]}},
-...     [{&#34;target&#34;: &#34;Test AndState&#34;,
-...       &#34;command&#34;: &#34;get state&#34;},
-...      {&#34;target&#34;: &#34;Test OrState&#34;,
-...       &#34;command&#34;: &#34;get state&#34;},
-...      {&#34;target&#34;: &#34;Test State&#34;,
-...       &#34;command&#34;: &#34;set state&#34;, &#34;new state&#34;: True},
-...      {&#34;target&#34;: &#34;Test StateAlias&#34;,
-...       &#34;command&#34;: &#34;set state&#34;, &#34;new state&#34;: True},
-...      {&#34;target&#34;: &#34;Test State&#34;,
-...       &#34;command&#34;: &#34;set state&#34;, &#34;new state&#34;: False}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test State&#39;, &#39;plugin&#39;: &#39;State&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                    &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                   {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                       &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test State 2&#39;, &#39;plugin&#39;: &#39;State&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                    &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                   {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                       &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test StateAlias&#39;, &#39;plugin&#39;: &#39;StateAlias&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                    &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                   {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                   {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                    &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                   {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                    &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                    &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                      {&#39;target&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                       &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                      {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                       &#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                       &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                      {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                       &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test AndState&#39;, &#39;plugin&#39;: &#39;AndState&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                    &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                   {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test AndState&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                      {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                       &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                      {&#39;sender&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                       &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test OrState&#39;, &#39;plugin&#39;: &#39;OrState&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                    &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                   {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test OrState&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                      {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                       &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                      {&#39;sender&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                       &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,
-         &#39;command&#39;: &#39;get state&#39;}
-test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: False}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,
-         &#39;command&#39;: &#39;get state&#39;}
-test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: False}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,
-         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State 2&#39;,
-         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-         &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}
-test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-&#34;&#34;&#34;
-from controlpi import BasePlugin, Message, MessageTemplate
-
-from typing import Dict
-
-
-class State(BasePlugin):
-    &#34;&#34;&#34;Provide a Boolean state.
-
-    The state of a State plugin instance can be queried with the &#34;get state&#34;
-    command and set with the &#34;set state&#34; command to the new state given by
-    the &#34;new state&#34; key:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State&#34;: {&#34;plugin&#34;: &#34;State&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;get state&#34;},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = True
-    &#34;&#34;&#34;Schema for State plugin configuration.
-
-    There are no required or optional configuration keys.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Process commands to get/set state.&#34;&#34;&#34;
-        if message[&#39;command&#39;] == &#39;get state&#39;:
-            await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-        elif message[&#39;command&#39;] == &#39;set state&#39;:
-            if self.state != message[&#39;new state&#39;]:
-                assert isinstance(message[&#39;new state&#39;], bool)
-                self.state: bool = message[&#39;new state&#39;]
-                await self.bus.send(Message(self.name,
-                                            {&#39;event&#39;: &#39;changed&#39;,
-                                             &#39;state&#39;: self.state}))
-            else:
-                await self.bus.send(Message(self.name,
-                                            {&#39;state&#39;: self.state}))
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.state = False
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                    MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                     &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        self.bus.register(self.name, &#39;State&#39;, sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass
-
-
-class StateAlias(BasePlugin):
-    &#34;&#34;&#34;Define an alias for another state.
-
-    The &#34;alias for&#34; configuration key gets the name for the other state that
-    is aliased by the StateAlias plugin instance.
-
-    The &#34;get state&#34; and &#34;set state&#34; commands are forwarded to and the
-    &#34;changed&#34; events and &#34;state&#34; messages are forwarded from this other
-    state:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test StateAlias&#34;: {&#34;plugin&#34;: &#34;StateAlias&#34;,
-    ...                          &#34;alias for&#34;: &#34;Test State&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;get state&#34;},
-    ...      {&#34;target&#34;: &#34;Test StateAlias&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test StateAlias&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test StateAlias&#39;, &#39;plugin&#39;: &#39;StateAlias&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                        &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                       {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                        &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                        &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;alias for&#39;: {&#39;type&#39;: &#39;string&#39;}},
-                   &#39;required&#39;: [&#39;alias for&#39;]}
-    &#34;&#34;&#34;Schema for StateAlias plugin configuration.
-
-    Required configuration key:
-
-    - &#39;alias for&#39;: name of aliased state.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Translate states from and commands to aliased state.&#34;&#34;&#34;
-        alias_message = Message(self.name)
-        if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-                &#39;command&#39; in message):
-            alias_message[&#39;target&#39;] = self.conf[&#39;alias for&#39;]
-            if message[&#39;command&#39;] == &#39;get state&#39;:
-                alias_message[&#39;command&#39;] = &#39;get state&#39;
-                await self.bus.send(alias_message)
-            elif (message[&#39;command&#39;] == &#39;set state&#39; and
-                    &#39;new state&#39; in message):
-                alias_message[&#39;command&#39;] = &#39;set state&#39;
-                alias_message[&#39;new state&#39;] = message[&#39;new state&#39;]
-                await self.bus.send(alias_message)
-        if (message[&#39;sender&#39;] == self.conf[&#39;alias for&#39;] and
-                &#39;state&#39; in message):
-            if &#39;event&#39; in message and message[&#39;event&#39;] == &#39;changed&#39;:
-                alias_message[&#39;event&#39;] = &#39;changed&#39;
-            alias_message[&#39;state&#39;] = message[&#39;state&#39;]
-            await self.bus.send(alias_message)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        sends = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                  &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                 MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                  &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                  &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                    MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                     &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                    MessageTemplate({&#39;sender&#39;:
-                                     {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                     &#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                     &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                    MessageTemplate({&#39;sender&#39;:
-                                     {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                     &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        self.bus.register(self.name, &#39;StateAlias&#39;,
-                          sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass
-
-
-class AndState(BasePlugin):
-    &#34;&#34;&#34;Implement conjunction of states.
-
-    The &#34;states&#34; configuration key gets an array of states to be combined.
-    An AndState plugin client reacts to &#34;get state&#34; commands and sends
-    &#34;changed&#34; events when a change in one of the combined states leads to
-    a change for the conjunction:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State 1&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test State 2&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test AndState&#34;: {&#34;plugin&#34;: &#34;AndState&#34;,
-    ...                        &#34;states&#34;: [&#34;Test State 1&#34;, &#34;Test State 2&#34;]}},
-    ...     [{&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 2&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: False},
-    ...      {&#34;target&#34;: &#34;Test AndState&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 1&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 2&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test AndState&#39;, &#39;plugin&#39;: &#39;AndState&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test AndState&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: False}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;states&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                             &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}},
-                   &#39;required&#39;: [&#39;states&#39;]}
-    &#34;&#34;&#34;Schema for AndState plugin configuration.
-
-    Required configuration key:
-
-    - &#39;states&#39;: list of names of combined states.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Process &#34;get state&#34; command and messages of combined states.&#34;&#34;&#34;
-        if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-                &#39;command&#39; in message and message[&#39;command&#39;] == &#39;get state&#39;):
-            await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-        if &#39;state&#39; in message and message[&#39;sender&#39;] in self.conf[&#39;states&#39;]:
-            assert isinstance(message[&#39;sender&#39;], str)
-            assert isinstance(message[&#39;state&#39;], bool)
-            self.states[message[&#39;sender&#39;]] = message[&#39;state&#39;]
-            new_state = all(self.states.values())
-            if self.state != new_state:
-                self.state: bool = new_state
-                await self.bus.send(Message(self.name,
-                                            {&#39;event&#39;: &#39;changed&#39;,
-                                             &#39;state&#39;: self.state}))
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}})]
-        self.states: Dict[str, bool] = {}
-        for state in self.conf[&#39;states&#39;]:
-            receives.append(MessageTemplate({&#39;sender&#39;: {&#39;const&#39;: state},
-                                             &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}))
-            self.states[state] = False
-        self.state = all(self.states.values())
-        self.bus.register(self.name, &#39;AndState&#39;,
-                          sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass
-
-
-class OrState(BasePlugin):
-    &#34;&#34;&#34;Implement disjunction of states.
-
-    The &#34;states&#34; configuration key gets an array of states to be combined.
-    An OrState plugin client reacts to &#34;get state&#34; commands and sends
-    &#34;changed&#34; events when a change in one of the combined states leads to
-    a change for the disjunction:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State 1&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test State 2&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test OrState&#34;: {&#34;plugin&#34;: &#34;OrState&#34;,
-    ...                       &#34;states&#34;: [&#34;Test State 1&#34;, &#34;Test State 2&#34;]}},
-    ...     [{&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 2&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: False},
-    ...      {&#34;target&#34;: &#34;Test OrState&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 1&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 2&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test OrState&#39;, &#39;plugin&#39;: &#39;OrState&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test OrState&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: True}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;states&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                             &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}},
-                   &#39;required&#39;: [&#39;states&#39;]}
-    &#34;&#34;&#34;Schema for OrState plugin configuration.
-
-    Required configuration key:
-
-    - &#39;states&#39;: list of names of combined states.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Process &#34;get state&#34; command and messages of combined states.&#34;&#34;&#34;
-        if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-                &#39;command&#39; in message and message[&#39;command&#39;] == &#39;get state&#39;):
-            await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-        if &#39;state&#39; in message and message[&#39;sender&#39;] in self.conf[&#39;states&#39;]:
-            assert isinstance(message[&#39;sender&#39;], str)
-            assert isinstance(message[&#39;state&#39;], bool)
-            self.states[message[&#39;sender&#39;]] = message[&#39;state&#39;]
-            new_state = any(self.states.values())
-            if self.state != new_state:
-                self.state: bool = new_state
-                await self.bus.send(Message(self.name,
-                                            {&#39;event&#39;: &#39;changed&#39;,
-                                             &#39;state&#39;: self.state}))
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}})]
-        self.states: Dict[str, bool] = {}
-        for state in self.conf[&#39;states&#39;]:
-            receives.append(MessageTemplate({&#39;sender&#39;: {&#39;const&#39;: state},
-                                             &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}))
-            self.states[state] = False
-        self.state = any(self.states.values())
-        self.bus.register(self.name, &#39;OrState&#39;,
-                          sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-classes">Classes</h2>
-<dl>
-<dt id="controlpi_plugins.state.State"><code class="flex name class">
-<span>class <span class="ident">State</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Provide a Boolean state.</p>
-<p>The state of a State plugin instance can be queried with the "get state"
-command and set with the "set state" command to the new state given by
-the "new state" key:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import asyncio
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;}},
-...     [{&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;},
-...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'get state'}
-test(): {'sender': 'Test State', 'state': False}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'get state'}
-test(): {'sender': 'Test State', 'state': True}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class State(BasePlugin):
-    &#34;&#34;&#34;Provide a Boolean state.
-
-    The state of a State plugin instance can be queried with the &#34;get state&#34;
-    command and set with the &#34;set state&#34; command to the new state given by
-    the &#34;new state&#34; key:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State&#34;: {&#34;plugin&#34;: &#34;State&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;get state&#34;},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = True
-    &#34;&#34;&#34;Schema for State plugin configuration.
-
-    There are no required or optional configuration keys.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Process commands to get/set state.&#34;&#34;&#34;
-        if message[&#39;command&#39;] == &#39;get state&#39;:
-            await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-        elif message[&#39;command&#39;] == &#39;set state&#39;:
-            if self.state != message[&#39;new state&#39;]:
-                assert isinstance(message[&#39;new state&#39;], bool)
-                self.state: bool = message[&#39;new state&#39;]
-                await self.bus.send(Message(self.name,
-                                            {&#39;event&#39;: &#39;changed&#39;,
-                                             &#39;state&#39;: self.state}))
-            else:
-                await self.bus.send(Message(self.name,
-                                            {&#39;state&#39;: self.state}))
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.state = False
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                    MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                     &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        self.bus.register(self.name, &#39;State&#39;, sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.state.State.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for State plugin configuration.</p>
-<p>There are no required or optional configuration keys.</p></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.state.State.receive"><code class="name flex">
-<span>async def <span class="ident">receive</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Process commands to get/set state.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def receive(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Process commands to get/set state.&#34;&#34;&#34;
-    if message[&#39;command&#39;] == &#39;get state&#39;:
-        await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-    elif message[&#39;command&#39;] == &#39;set state&#39;:
-        if self.state != message[&#39;new state&#39;]:
-            assert isinstance(message[&#39;new state&#39;], bool)
-            self.state: bool = message[&#39;new state&#39;]
-            await self.bus.send(Message(self.name,
-                                        {&#39;event&#39;: &#39;changed&#39;,
-                                         &#39;state&#39;: self.state}))
-        else:
-            await self.bus.send(Message(self.name,
-                                        {&#39;state&#39;: self.state}))</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.State.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    self.state = False
-    sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                              &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-             MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                 &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-    self.bus.register(self.name, &#39;State&#39;, sends, receives, self.receive)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.State.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.state.StateAlias"><code class="flex name class">
-<span>class <span class="ident">StateAlias</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Define an alias for another state.</p>
-<p>The "alias for" configuration key gets the name for the other state that
-is aliased by the StateAlias plugin instance.</p>
-<p>The "get state" and "set state" commands are forwarded to and the
-"changed" events and "state" messages are forwarded from this other
-state:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import asyncio
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test State&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test StateAlias&quot;: {&quot;plugin&quot;: &quot;StateAlias&quot;,
-...                          &quot;alias for&quot;: &quot;Test State&quot;}},
-...     [{&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;get state&quot;},
-...      {&quot;target&quot;: &quot;Test StateAlias&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test StateAlias&quot;, &quot;command&quot;: &quot;get state&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test StateAlias', 'plugin': 'StateAlias',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}},
-                   {'target': {'const': 'Test State'},
-                    'command': {'const': 'get state'}},
-                   {'target': {'const': 'Test State'},
-                    'command': {'const': 'set state'},
-                    'new state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test StateAlias'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test StateAlias'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test State'},
-                       'event': {'const': 'changed'},
-                       'state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test State'},
-                       'state': {'type': 'boolean'}}]}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'get state'}
-test(): {'sender': 'Test State', 'state': False}
-test(): {'sender': 'Test StateAlias', 'state': False}
-test(): {'sender': 'test()', 'target': 'Test StateAlias',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test StateAlias', 'target': 'Test State',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State', 'event': 'changed', 'state': True}
-test(): {'sender': 'Test StateAlias', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State', 'state': True}
-test(): {'sender': 'Test StateAlias', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test StateAlias',
-         'command': 'get state'}
-test(): {'sender': 'Test StateAlias', 'target': 'Test State',
-         'command': 'get state'}
-test(): {'sender': 'Test State', 'state': True}
-test(): {'sender': 'Test StateAlias', 'state': True}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class StateAlias(BasePlugin):
-    &#34;&#34;&#34;Define an alias for another state.
-
-    The &#34;alias for&#34; configuration key gets the name for the other state that
-    is aliased by the StateAlias plugin instance.
-
-    The &#34;get state&#34; and &#34;set state&#34; commands are forwarded to and the
-    &#34;changed&#34; events and &#34;state&#34; messages are forwarded from this other
-    state:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test StateAlias&#34;: {&#34;plugin&#34;: &#34;StateAlias&#34;,
-    ...                          &#34;alias for&#34;: &#34;Test State&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;get state&#34;},
-    ...      {&#34;target&#34;: &#34;Test StateAlias&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test StateAlias&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test StateAlias&#39;, &#39;plugin&#39;: &#39;StateAlias&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                        &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                       {&#39;target&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                        &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                        &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test StateAlias&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test StateAlias&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;target&#39;: &#39;Test State&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test State&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test StateAlias&#39;, &#39;state&#39;: True}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;alias for&#39;: {&#39;type&#39;: &#39;string&#39;}},
-                   &#39;required&#39;: [&#39;alias for&#39;]}
-    &#34;&#34;&#34;Schema for StateAlias plugin configuration.
-
-    Required configuration key:
-
-    - &#39;alias for&#39;: name of aliased state.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Translate states from and commands to aliased state.&#34;&#34;&#34;
-        alias_message = Message(self.name)
-        if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-                &#39;command&#39; in message):
-            alias_message[&#39;target&#39;] = self.conf[&#39;alias for&#39;]
-            if message[&#39;command&#39;] == &#39;get state&#39;:
-                alias_message[&#39;command&#39;] = &#39;get state&#39;
-                await self.bus.send(alias_message)
-            elif (message[&#39;command&#39;] == &#39;set state&#39; and
-                    &#39;new state&#39; in message):
-                alias_message[&#39;command&#39;] = &#39;set state&#39;
-                alias_message[&#39;new state&#39;] = message[&#39;new state&#39;]
-                await self.bus.send(alias_message)
-        if (message[&#39;sender&#39;] == self.conf[&#39;alias for&#39;] and
-                &#39;state&#39; in message):
-            if &#39;event&#39; in message and message[&#39;event&#39;] == &#39;changed&#39;:
-                alias_message[&#39;event&#39;] = &#39;changed&#39;
-            alias_message[&#39;state&#39;] = message[&#39;state&#39;]
-            await self.bus.send(alias_message)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        sends = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                  &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                 MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                  &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                  &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                    MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                     &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                    MessageTemplate({&#39;sender&#39;:
-                                     {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                     &#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                     &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                    MessageTemplate({&#39;sender&#39;:
-                                     {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                     &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        self.bus.register(self.name, &#39;StateAlias&#39;,
-                          sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.state.StateAlias.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for StateAlias plugin configuration.</p>
-<p>Required configuration key:</p>
-<ul>
-<li>'alias for': name of aliased state.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.state.StateAlias.receive"><code class="name flex">
-<span>async def <span class="ident">receive</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Translate states from and commands to aliased state.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def receive(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Translate states from and commands to aliased state.&#34;&#34;&#34;
-    alias_message = Message(self.name)
-    if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-            &#39;command&#39; in message):
-        alias_message[&#39;target&#39;] = self.conf[&#39;alias for&#39;]
-        if message[&#39;command&#39;] == &#39;get state&#39;:
-            alias_message[&#39;command&#39;] = &#39;get state&#39;
-            await self.bus.send(alias_message)
-        elif (message[&#39;command&#39;] == &#39;set state&#39; and
-                &#39;new state&#39; in message):
-            alias_message[&#39;command&#39;] = &#39;set state&#39;
-            alias_message[&#39;new state&#39;] = message[&#39;new state&#39;]
-            await self.bus.send(alias_message)
-    if (message[&#39;sender&#39;] == self.conf[&#39;alias for&#39;] and
-            &#39;state&#39; in message):
-        if &#39;event&#39; in message and message[&#39;event&#39;] == &#39;changed&#39;:
-            alias_message[&#39;event&#39;] = &#39;changed&#39;
-        alias_message[&#39;state&#39;] = message[&#39;state&#39;]
-        await self.bus.send(alias_message)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.StateAlias.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    sends = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                              &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-             MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                              &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                              &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-             MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                              &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-             MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}}),
-                MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                                 &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                MessageTemplate({&#39;sender&#39;:
-                                 {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                 &#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                 &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                MessageTemplate({&#39;sender&#39;:
-                                 {&#39;const&#39;: self.conf[&#39;alias for&#39;]},
-                                 &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-    self.bus.register(self.name, &#39;StateAlias&#39;,
-                      sends, receives, self.receive)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.StateAlias.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.state.AndState"><code class="flex name class">
-<span>class <span class="ident">AndState</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Implement conjunction of states.</p>
-<p>The "states" configuration key gets an array of states to be combined.
-An AndState plugin client reacts to "get state" commands and sends
-"changed" events when a change in one of the combined states leads to
-a change for the conjunction:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import asyncio
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test AndState&quot;: {&quot;plugin&quot;: &quot;AndState&quot;,
-...                        &quot;states&quot;: [&quot;Test State 1&quot;, &quot;Test State 2&quot;]}},
-...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: False},
-...      {&quot;target&quot;: &quot;Test AndState&quot;, &quot;command&quot;: &quot;get state&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State 1', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State 1'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State 1'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State 2', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State 2'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State 2'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test AndState', 'plugin': 'AndState',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test AndState'},
-                       'command': {'const': 'get state'}},
-                      {'sender': {'const': 'Test State 1'},
-                       'state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test State 2'},
-                       'state': {'type': 'boolean'}}]}
-test(): {'sender': 'test()', 'target': 'Test State 1',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State 1', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State 2',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State 2', 'event': 'changed', 'state': True}
-test(): {'sender': 'Test AndState', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State 1',
-         'command': 'set state', 'new state': False}
-test(): {'sender': 'Test State 1', 'event': 'changed', 'state': False}
-test(): {'sender': 'Test AndState', 'event': 'changed', 'state': False}
-test(): {'sender': 'test()', 'target': 'Test AndState',
-         'command': 'get state'}
-test(): {'sender': 'Test AndState', 'state': False}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class AndState(BasePlugin):
-    &#34;&#34;&#34;Implement conjunction of states.
-
-    The &#34;states&#34; configuration key gets an array of states to be combined.
-    An AndState plugin client reacts to &#34;get state&#34; commands and sends
-    &#34;changed&#34; events when a change in one of the combined states leads to
-    a change for the conjunction:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State 1&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test State 2&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test AndState&#34;: {&#34;plugin&#34;: &#34;AndState&#34;,
-    ...                        &#34;states&#34;: [&#34;Test State 1&#34;, &#34;Test State 2&#34;]}},
-    ...     [{&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 2&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: False},
-    ...      {&#34;target&#34;: &#34;Test AndState&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 1&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 2&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test AndState&#39;, &#39;plugin&#39;: &#39;AndState&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test AndState&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test AndState&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test AndState&#39;, &#39;state&#39;: False}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;states&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                             &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}},
-                   &#39;required&#39;: [&#39;states&#39;]}
-    &#34;&#34;&#34;Schema for AndState plugin configuration.
-
-    Required configuration key:
-
-    - &#39;states&#39;: list of names of combined states.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Process &#34;get state&#34; command and messages of combined states.&#34;&#34;&#34;
-        if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-                &#39;command&#39; in message and message[&#39;command&#39;] == &#39;get state&#39;):
-            await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-        if &#39;state&#39; in message and message[&#39;sender&#39;] in self.conf[&#39;states&#39;]:
-            assert isinstance(message[&#39;sender&#39;], str)
-            assert isinstance(message[&#39;state&#39;], bool)
-            self.states[message[&#39;sender&#39;]] = message[&#39;state&#39;]
-            new_state = all(self.states.values())
-            if self.state != new_state:
-                self.state: bool = new_state
-                await self.bus.send(Message(self.name,
-                                            {&#39;event&#39;: &#39;changed&#39;,
-                                             &#39;state&#39;: self.state}))
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}})]
-        self.states: Dict[str, bool] = {}
-        for state in self.conf[&#39;states&#39;]:
-            receives.append(MessageTemplate({&#39;sender&#39;: {&#39;const&#39;: state},
-                                             &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}))
-            self.states[state] = False
-        self.state = all(self.states.values())
-        self.bus.register(self.name, &#39;AndState&#39;,
-                          sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.state.AndState.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for AndState plugin configuration.</p>
-<p>Required configuration key:</p>
-<ul>
-<li>'states': list of names of combined states.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.state.AndState.receive"><code class="name flex">
-<span>async def <span class="ident">receive</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Process "get state" command and messages of combined states.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def receive(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Process &#34;get state&#34; command and messages of combined states.&#34;&#34;&#34;
-    if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-            &#39;command&#39; in message and message[&#39;command&#39;] == &#39;get state&#39;):
-        await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-    if &#39;state&#39; in message and message[&#39;sender&#39;] in self.conf[&#39;states&#39;]:
-        assert isinstance(message[&#39;sender&#39;], str)
-        assert isinstance(message[&#39;state&#39;], bool)
-        self.states[message[&#39;sender&#39;]] = message[&#39;state&#39;]
-        new_state = all(self.states.values())
-        if self.state != new_state:
-            self.state: bool = new_state
-            await self.bus.send(Message(self.name,
-                                        {&#39;event&#39;: &#39;changed&#39;,
-                                         &#39;state&#39;: self.state}))</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.AndState.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                              &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-             MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}})]
-    self.states: Dict[str, bool] = {}
-    for state in self.conf[&#39;states&#39;]:
-        receives.append(MessageTemplate({&#39;sender&#39;: {&#39;const&#39;: state},
-                                         &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}))
-        self.states[state] = False
-    self.state = all(self.states.values())
-    self.bus.register(self.name, &#39;AndState&#39;,
-                      sends, receives, self.receive)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.AndState.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.state.OrState"><code class="flex name class">
-<span>class <span class="ident">OrState</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Implement disjunction of states.</p>
-<p>The "states" configuration key gets an array of states to be combined.
-An OrState plugin client reacts to "get state" commands and sends
-"changed" events when a change in one of the combined states leads to
-a change for the disjunction:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import asyncio
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test State 1&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test State 2&quot;: {&quot;plugin&quot;: &quot;State&quot;},
-...      &quot;Test OrState&quot;: {&quot;plugin&quot;: &quot;OrState&quot;,
-...                       &quot;states&quot;: [&quot;Test State 1&quot;, &quot;Test State 2&quot;]}},
-...     [{&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State 2&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: True},
-...      {&quot;target&quot;: &quot;Test State 1&quot;, &quot;command&quot;: &quot;set state&quot;,
-...       &quot;new state&quot;: False},
-...      {&quot;target&quot;: &quot;Test OrState&quot;, &quot;command&quot;: &quot;get state&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State 1', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State 1'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State 1'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test State 2', 'plugin': 'State',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test State 2'},
-                       'command': {'const': 'get state'}},
-                      {'target': {'const': 'Test State 2'},
-                       'command': {'const': 'set state'},
-                       'new state': {'type': 'boolean'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test OrState', 'plugin': 'OrState',
-         'sends': [{'event': {'const': 'changed'},
-                    'state': {'type': 'boolean'}},
-                   {'state': {'type': 'boolean'}}],
-         'receives': [{'target': {'const': 'Test OrState'},
-                       'command': {'const': 'get state'}},
-                      {'sender': {'const': 'Test State 1'},
-                       'state': {'type': 'boolean'}},
-                      {'sender': {'const': 'Test State 2'},
-                       'state': {'type': 'boolean'}}]}
-test(): {'sender': 'test()', 'target': 'Test State 1',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State 1', 'event': 'changed', 'state': True}
-test(): {'sender': 'Test OrState', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State 2',
-         'command': 'set state', 'new state': True}
-test(): {'sender': 'Test State 2', 'event': 'changed', 'state': True}
-test(): {'sender': 'test()', 'target': 'Test State 1',
-         'command': 'set state', 'new state': False}
-test(): {'sender': 'Test State 1', 'event': 'changed', 'state': False}
-test(): {'sender': 'test()', 'target': 'Test OrState',
-         'command': 'get state'}
-test(): {'sender': 'Test OrState', 'state': True}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class OrState(BasePlugin):
-    &#34;&#34;&#34;Implement disjunction of states.
-
-    The &#34;states&#34; configuration key gets an array of states to be combined.
-    An OrState plugin client reacts to &#34;get state&#34; commands and sends
-    &#34;changed&#34; events when a change in one of the combined states leads to
-    a change for the disjunction:
-    &gt;&gt;&gt; import asyncio
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test State 1&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test State 2&#34;: {&#34;plugin&#34;: &#34;State&#34;},
-    ...      &#34;Test OrState&#34;: {&#34;plugin&#34;: &#34;OrState&#34;,
-    ...                       &#34;states&#34;: [&#34;Test State 1&#34;, &#34;Test State 2&#34;]}},
-    ...     [{&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 2&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: True},
-    ...      {&#34;target&#34;: &#34;Test State 1&#34;, &#34;command&#34;: &#34;set state&#34;,
-    ...       &#34;new state&#34;: False},
-    ...      {&#34;target&#34;: &#34;Test OrState&#34;, &#34;command&#34;: &#34;get state&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 1&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test State 2&#39;, &#39;plugin&#39;: &#39;State&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set state&#39;},
-                           &#39;new state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test OrState&#39;, &#39;plugin&#39;: &#39;OrState&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                        &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                       {&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test OrState&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 1&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}},
-                          {&#39;sender&#39;: {&#39;const&#39;: &#39;Test State 2&#39;},
-                           &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 2&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;Test State 2&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: True}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test State 1&#39;,
-             &#39;command&#39;: &#39;set state&#39;, &#39;new state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;Test State 1&#39;, &#39;event&#39;: &#39;changed&#39;, &#39;state&#39;: False}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test OrState&#39;,
-             &#39;command&#39;: &#39;get state&#39;}
-    test(): {&#39;sender&#39;: &#39;Test OrState&#39;, &#39;state&#39;: True}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;states&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                             &#39;items&#39;: {&#39;type&#39;: &#39;string&#39;}}},
-                   &#39;required&#39;: [&#39;states&#39;]}
-    &#34;&#34;&#34;Schema for OrState plugin configuration.
-
-    Required configuration key:
-
-    - &#39;states&#39;: list of names of combined states.
-    &#34;&#34;&#34;
-
-    async def receive(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Process &#34;get state&#34; command and messages of combined states.&#34;&#34;&#34;
-        if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-                &#39;command&#39; in message and message[&#39;command&#39;] == &#39;get state&#39;):
-            await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-        if &#39;state&#39; in message and message[&#39;sender&#39;] in self.conf[&#39;states&#39;]:
-            assert isinstance(message[&#39;sender&#39;], str)
-            assert isinstance(message[&#39;state&#39;], bool)
-            self.states[message[&#39;sender&#39;]] = message[&#39;state&#39;]
-            new_state = any(self.states.values())
-            if self.state != new_state:
-                self.state: bool = new_state
-                await self.bus.send(Message(self.name,
-                                            {&#39;event&#39;: &#39;changed&#39;,
-                                             &#39;state&#39;: self.state}))
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                                  &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-                 MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}})]
-        self.states: Dict[str, bool] = {}
-        for state in self.conf[&#39;states&#39;]:
-            receives.append(MessageTemplate({&#39;sender&#39;: {&#39;const&#39;: state},
-                                             &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}))
-            self.states[state] = False
-        self.state = any(self.states.values())
-        self.bus.register(self.name, &#39;OrState&#39;,
-                          sends, receives, self.receive)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.state.OrState.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for OrState plugin configuration.</p>
-<p>Required configuration key:</p>
-<ul>
-<li>'states': list of names of combined states.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.state.OrState.receive"><code class="name flex">
-<span>async def <span class="ident">receive</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Process "get state" command and messages of combined states.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def receive(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Process &#34;get state&#34; command and messages of combined states.&#34;&#34;&#34;
-    if (&#39;target&#39; in message and message[&#39;target&#39;] == self.name and
-            &#39;command&#39; in message and message[&#39;command&#39;] == &#39;get state&#39;):
-        await self.bus.send(Message(self.name, {&#39;state&#39;: self.state}))
-    if &#39;state&#39; in message and message[&#39;sender&#39;] in self.conf[&#39;states&#39;]:
-        assert isinstance(message[&#39;sender&#39;], str)
-        assert isinstance(message[&#39;state&#39;], bool)
-        self.states[message[&#39;sender&#39;]] = message[&#39;state&#39;]
-        new_state = any(self.states.values())
-        if self.state != new_state:
-            self.state: bool = new_state
-            await self.bus.send(Message(self.name,
-                                        {&#39;event&#39;: &#39;changed&#39;,
-                                         &#39;state&#39;: self.state}))</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.OrState.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;changed&#39;},
-                              &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}),
-             MessageTemplate({&#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}})]
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;get state&#39;}})]
-    self.states: Dict[str, bool] = {}
-    for state in self.conf[&#39;states&#39;]:
-        receives.append(MessageTemplate({&#39;sender&#39;: {&#39;const&#39;: state},
-                                         &#39;state&#39;: {&#39;type&#39;: &#39;boolean&#39;}}))
-        self.states[state] = False
-    self.state = any(self.states.values())
-    self.bus.register(self.name, &#39;OrState&#39;,
-                      sends, receives, self.receive)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.state.OrState.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-</dl>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3>Super-module</h3>
-<ul>
-<li><code><a title="controlpi_plugins" href="index.html">controlpi_plugins</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-classes">Classes</a></h3>
-<ul>
-<li>
-<h4><code><a title="controlpi_plugins.state.State" href="#controlpi_plugins.state.State">State</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.state.State.receive" href="#controlpi_plugins.state.State.receive">receive</a></code></li>
-<li><code><a title="controlpi_plugins.state.State.process_conf" href="#controlpi_plugins.state.State.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.state.State.run" href="#controlpi_plugins.state.State.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.state.State.CONF_SCHEMA" href="#controlpi_plugins.state.State.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.state.StateAlias" href="#controlpi_plugins.state.StateAlias">StateAlias</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.state.StateAlias.receive" href="#controlpi_plugins.state.StateAlias.receive">receive</a></code></li>
-<li><code><a title="controlpi_plugins.state.StateAlias.process_conf" href="#controlpi_plugins.state.StateAlias.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.state.StateAlias.run" href="#controlpi_plugins.state.StateAlias.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.state.StateAlias.CONF_SCHEMA" href="#controlpi_plugins.state.StateAlias.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.state.AndState" href="#controlpi_plugins.state.AndState">AndState</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.state.AndState.receive" href="#controlpi_plugins.state.AndState.receive">receive</a></code></li>
-<li><code><a title="controlpi_plugins.state.AndState.process_conf" href="#controlpi_plugins.state.AndState.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.state.AndState.run" href="#controlpi_plugins.state.AndState.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.state.AndState.CONF_SCHEMA" href="#controlpi_plugins.state.AndState.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.state.OrState" href="#controlpi_plugins.state.OrState">OrState</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.state.OrState.receive" href="#controlpi_plugins.state.OrState.receive">receive</a></code></li>
-<li><code><a title="controlpi_plugins.state.OrState.process_conf" href="#controlpi_plugins.state.OrState.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.state.OrState.run" href="#controlpi_plugins.state.OrState.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.state.OrState.CONF_SCHEMA" href="#controlpi_plugins.state.OrState.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi_plugins/util.html b/doc/controlpi_plugins/util.html
deleted file mode 100644 (file)
index ca720bb..0000000
+++ /dev/null
@@ -1,1421 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi_plugins.util API documentation</title>
-<meta name="description" content="Provide utility plugins for all kinds of systems …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Module <code>controlpi_plugins.util</code></h1>
-</header>
-<section id="section-intro">
-<p>Provide utility plugins for all kinds of systems.</p>
-<ul>
-<li>Log logs messages on stdout.</li>
-<li>Init sends list of messages on startup and on demand.</li>
-<li>Alias translates messages to an alias.</li>
-</ul>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,
-...                   &quot;filter&quot;: [{&quot;sender&quot;: {&quot;const&quot;: &quot;Test Alias&quot;}}]},
-...      &quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,
-...                    &quot;messages&quot;: [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;}]},
-...      &quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,
-...                     &quot;from&quot;: {&quot;sender&quot;: {&quot;const&quot;: &quot;Test Init&quot;},
-...                              &quot;id&quot;: {&quot;const&quot;: 42}},
-...                     &quot;to&quot;: {&quot;id&quot;: &quot;translated&quot;}}}, []))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Log', 'plugin': 'Log',
-         'sends': [], 'receives': [{'sender': {'const': 'Test Alias'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Init', 'plugin': 'Init',
-         'sends': [{'id': {'const': 42},
-                    'content': {'const': 'Test Message'}}],
-         'receives': [{'target': {'const': 'Test Init'},
-                       'command': {'const': 'execute'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Alias', 'plugin': 'Alias',
-         'sends': [{'id': {'const': 'translated'}}],
-         'receives': [{'sender': {'const': 'Test Init'},
-                       'id': {'const': 42}}]}
-test(): {'sender': 'Test Init', 'id': 42,
-         'content': 'Test Message'}
-test(): {'sender': 'Test Alias', 'id': 'translated',
-         'content': 'Test Message'}
-Test Log: {'sender': 'Test Alias', 'id': 'translated',
-           'content': 'Test Message'}
-</code></pre>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Provide utility plugins for all kinds of systems.
-
-- Log logs messages on stdout.
-- Init sends list of messages on startup and on demand.
-- Alias translates messages to an alias.
-
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;,
-...                   &#34;filter&#34;: [{&#34;sender&#34;: {&#34;const&#34;: &#34;Test Alias&#34;}}]},
-...      &#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-...                    &#34;messages&#34;: [{&#34;id&#34;: 42, &#34;content&#34;: &#34;Test Message&#34;}]},
-...      &#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;,
-...                     &#34;from&#34;: {&#34;sender&#34;: {&#34;const&#34;: &#34;Test Init&#34;},
-...                              &#34;id&#34;: {&#34;const&#34;: 42}},
-...                     &#34;to&#34;: {&#34;id&#34;: &#34;translated&#34;}}}, []))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,
-         &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Alias&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,
-         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},
-                    &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,
-         &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],
-         &#39;receives&#39;: [{&#39;sender&#39;: {&#39;const&#39;: &#39;Test Init&#39;},
-                       &#39;id&#39;: {&#39;const&#39;: 42}}]}
-test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42,
-         &#39;content&#39;: &#39;Test Message&#39;}
-test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,
-         &#39;content&#39;: &#39;Test Message&#39;}
-Test Log: {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,
-           &#39;content&#39;: &#39;Test Message&#39;}
-&#34;&#34;&#34;
-import asyncio
-
-from controlpi import BasePlugin, Message, MessageTemplate
-
-
-class Log(BasePlugin):
-    &#34;&#34;&#34;Log messages on stdout.
-
-    The &#34;filter&#34; configuration key gets a list of message templates defining
-    the messages that should be logged by the plugin instance.
-
-    In the following example the first and third message match the given
-    template and are logged by the instance &#34;Test Log&#34;, while the second
-    message does not match and is only logged by the test, but not by the
-    Log instance:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;,
-    ...                   &#34;filter&#34;: [{&#34;id&#34;: {&#34;const&#34;: 42}}]}},
-    ...     [{&#34;id&#34;: 42, &#34;message&#34;: &#34;Test Message&#34;},
-    ...      {&#34;id&#34;: 42.42, &#34;message&#34;: &#34;Second Message&#34;},
-    ...      {&#34;id&#34;: 42, &#34;message&#34;: &#34;Third Message&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,
-             &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}
-    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42.42, &#39;message&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}
-    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}
-
-    The &#34;filter&#34; key is required:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;}}, []))
-    &#39;filter&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;filter&#39;: {&#39;items&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                   &#39;type&#39;: &#39;array&#39;}},
-         &#39;required&#39;: [&#39;filter&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Log&#39;}
-    Configuration for &#39;Test Log&#39; is not valid.
-
-    The &#34;filter&#34; key has to contain a list of message templates, i.e.,
-    JSON objects:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;,
-    ...                   &#34;filter&#34;: [42]}}, []))
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;filter&#39;][&#39;items&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;filter&#39;][0]:
-        42
-    Configuration for &#39;Test Log&#39; is not valid.
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;filter&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                             &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},
-                   &#39;required&#39;: [&#39;filter&#39;]}
-    &#34;&#34;&#34;Schema for Log plugin configuration.
-
-    Required configuration key:
-
-    - &#39;filter&#39;: list of message templates to be logged.
-    &#34;&#34;&#34;
-
-    async def log(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Log received message on stdout using own name as prefix.&#34;&#34;&#34;
-        print(f&#34;{self.name}: {message}&#34;)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.bus.register(self.name, &#39;Log&#39;, [], self.conf[&#39;filter&#39;], self.log)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass
-
-
-class Init(BasePlugin):
-    &#34;&#34;&#34;Send list of messages on startup and on demand.
-
-    The &#34;messages&#34; configuration key gets a list of messages to be sent on
-    startup. The same list is sent in reaction to a message with
-    &#34;target&#34;: &lt;name&gt; and &#34;command&#34;: &#34;execute&#34;.
-
-    In the example, the two configured messages are sent twice, once at
-    startup and a second time in reaction to the &#34;execute&#34; command sent by
-    the test:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-    ...                    &#34;messages&#34;: [{&#34;id&#34;: 42,
-    ...                                  &#34;content&#34;: &#34;Test Message&#34;},
-    ...                                 {&#34;id&#34;: 42.42,
-    ...                                  &#34;content&#34;: &#34;Second Message&#34;}]}},
-    ...     [{&#34;target&#34;: &#34;Test Init&#34;, &#34;command&#34;: &#34;execute&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,
-             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},
-                       {&#39;id&#39;: {&#39;const&#39;: 42.42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Init&#39;, &#39;command&#39;: &#39;execute&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-
-    The &#34;messages&#34; key is required:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;}}, []))
-    &#39;messages&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;messages&#39;: {&#39;items&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                     &#39;type&#39;: &#39;array&#39;}},
-         &#39;required&#39;: [&#39;messages&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Init&#39;}
-    Configuration for &#39;Test Init&#39; is not valid.
-
-    The &#34;messages&#34; key has to contain a list of (partial) messages, i.e.,
-    JSON objects:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-    ...                    &#34;messages&#34;: [42]}}, []))
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;messages&#39;][&#39;items&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;messages&#39;][0]:
-        42
-    Configuration for &#39;Test Init&#39; is not valid.
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                               &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},
-                   &#39;required&#39;: [&#39;messages&#39;]}
-    &#34;&#34;&#34;Schema for Init plugin configuration.
-
-    Required configuration key:
-
-    - &#39;messages&#39;: list of messages to be sent.
-    &#34;&#34;&#34;
-
-    async def execute(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Send configured messages.&#34;&#34;&#34;
-        for message in self.conf[&#39;messages&#39;]:
-            await self.bus.send(Message(self.name, message))
-            # Give immediate reactions to messages opportunity to happen:
-            await asyncio.sleep(0)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}})]
-        sends = [MessageTemplate.from_message(message)
-                 for message in self.conf[&#39;messages&#39;]]
-        self.bus.register(self.name, &#39;Init&#39;, sends, receives, self.execute)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Send configured messages on startup.&#34;&#34;&#34;
-        for message in self.conf[&#39;messages&#39;]:
-            await self.bus.send(Message(self.name, message))
-
-
-class Execute(BasePlugin):
-    &#34;&#34;&#34;Send configurable list of messages on demand.
-
-    An Execute plugin instance receives two kinds of commands.
-    The &#34;set messages&#34; command has a &#34;messages&#34; key with a list of (partial)
-    messages, which are sent by the Execute instance in reaction to an
-    &#34;execute&#34; command.
-
-    In the example, the first command sent by the test sets two messages,
-    which are then sent in reaction to the second command sent by the test:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Execute&#34;: {&#34;plugin&#34;: &#34;Execute&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test Execute&#34;, &#34;command&#34;: &#34;set messages&#34;,
-    ...       &#34;messages&#34;: [{&#34;id&#34;: 42, &#34;content&#34;: &#34;Test Message&#34;},
-    ...                    {&#34;id&#34;: 42.42, &#34;content&#34;: &#34;Second Message&#34;}]},
-    ...      {&#34;target&#34;: &#34;Test Execute&#34;, &#34;command&#34;: &#34;execute&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Execute&#39;, &#39;plugin&#39;: &#39;Execute&#39;,
-             &#39;sends&#39;: [{}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},
-                           &#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                        &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,
-             &#39;command&#39;: &#39;set messages&#39;,
-             &#39;messages&#39;: [{&#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;},
-                          {&#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,
-             &#39;command&#39;: &#39;execute&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42,
-             &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42.42,
-             &#39;content&#39;: &#39;Second Message&#39;}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = True
-    &#34;&#34;&#34;Schema for Execute plugin configuration.
-
-    There are no required or optional configuration keys.
-    &#34;&#34;&#34;
-
-    async def execute(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Set or send configured messages.&#34;&#34;&#34;
-        if message[&#39;command&#39;] == &#39;set messages&#39;:
-            assert isinstance(message[&#39;messages&#39;], list)
-            self.messages = list(message[&#39;messages&#39;])
-        elif message[&#39;command&#39;] == &#39;execute&#39;:
-            for message in self.messages:
-                await self.bus.send(Message(self.name, message))
-                # Give immediate reactions to messages opportunity to happen:
-                await asyncio.sleep(0)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.messages = []
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},
-                                     &#39;messages&#39;:
-                                     {&#39;type&#39;: &#39;array&#39;,
-                                      &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}}),
-                    MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}})]
-        sends = [MessageTemplate()]
-        self.bus.register(self.name, &#39;Execute&#39;, sends, receives, self.execute)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass
-
-
-class Alias(BasePlugin):
-    &#34;&#34;&#34;Translate messages to an alias.
-
-    The &#34;from&#34; configuration key gets a message template and the
-    configuration key &#34;to&#34; a (partial) message. All messages matching the
-    template are received by the Alias instance and a message translated by
-    removing the keys of the &#34;from&#34; template and adding the keys and values
-    of the &#34;to&#34; message is sent. Keys that are neither in &#34;from&#34; nor in &#34;to&#34;
-    are retained.
-
-    In the example, the two messages sent by the test are translated by the
-    Alias instance and the translated messages are sent by it preserving
-    the &#34;content&#34; keys:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;,
-    ...                     &#34;from&#34;: {&#34;id&#34;: {&#34;const&#34;: 42}},
-    ...                     &#34;to&#34;: {&#34;id&#34;: &#34;translated&#34;}}},
-    ...     [{&#34;id&#34;: 42, &#34;content&#34;: &#34;Test Message&#34;},
-    ...      {&#34;id&#34;: 42, &#34;content&#34;: &#34;Second Message&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,
-             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],
-             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,
-             &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,
-             &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,
-             &#39;content&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,
-             &#39;content&#39;: &#39;Second Message&#39;}
-
-    The &#34;from&#34; and &#34;to&#34; keys are required:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;}}, []))
-    &#39;from&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;}, &#39;to&#39;: {&#39;type&#39;: &#39;object&#39;}},
-         &#39;required&#39;: [&#39;from&#39;, &#39;to&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Alias&#39;}
-    &#39;to&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;}, &#39;to&#39;: {&#39;type&#39;: &#39;object&#39;}},
-         &#39;required&#39;: [&#39;from&#39;, &#39;to&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Alias&#39;}
-    Configuration for &#39;Test Alias&#39; is not valid.
-
-    The &#34;from&#34; key has to contain a message template and the &#34;to&#34; key a
-    (partial) message, i.e., both have to be JSON objects:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;,
-    ...                     &#34;from&#34;: 42,
-    ...                     &#34;to&#34;: 42}}, []))
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;from&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;from&#39;]:
-        42
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;to&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;to&#39;]:
-        42
-    Configuration for &#39;Test Alias&#39; is not valid.
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                  &#39;to&#39;: {&#39;type&#39;: &#39;object&#39;}},
-                   &#39;required&#39;: [&#39;from&#39;, &#39;to&#39;]}
-    &#34;&#34;&#34;Schema for Alias plugin configuration.
-
-    Required configuration keys:
-
-    - &#39;from&#39;: template of messages to be translated.
-    - &#39;to&#39;: translated message to be sent.
-    &#34;&#34;&#34;
-
-    async def alias(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Translate and send message.&#34;&#34;&#34;
-        alias_message = Message(self.name)
-        alias_message.update(self.conf[&#39;to&#39;])
-        for key in message:
-            if key != &#39;sender&#39; and key not in self.conf[&#39;from&#39;]:
-                alias_message[key] = message[key]
-        await self.bus.send(alias_message)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.bus.register(self.name, &#39;Alias&#39;,
-                          [MessageTemplate.from_message(self.conf[&#39;to&#39;])],
-                          [self.conf[&#39;from&#39;]],
-                          self.alias)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-classes">Classes</h2>
-<dl>
-<dt id="controlpi_plugins.util.Log"><code class="flex name class">
-<span>class <span class="ident">Log</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Log messages on stdout.</p>
-<p>The "filter" configuration key gets a list of message templates defining
-the messages that should be logged by the plugin instance.</p>
-<p>In the following example the first and third message match the given
-template and are logged by the instance "Test Log", while the second
-message does not match and is only logged by the test, but not by the
-Log instance:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,
-...                   &quot;filter&quot;: [{&quot;id&quot;: {&quot;const&quot;: 42}}]}},
-...     [{&quot;id&quot;: 42, &quot;message&quot;: &quot;Test Message&quot;},
-...      {&quot;id&quot;: 42.42, &quot;message&quot;: &quot;Second Message&quot;},
-...      {&quot;id&quot;: 42, &quot;message&quot;: &quot;Third Message&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Log', 'plugin': 'Log',
-         'sends': [], 'receives': [{'id': {'const': 42}}]}
-test(): {'sender': 'test()', 'id': 42, 'message': 'Test Message'}
-Test Log: {'sender': 'test()', 'id': 42, 'message': 'Test Message'}
-test(): {'sender': 'test()', 'id': 42.42, 'message': 'Second Message'}
-test(): {'sender': 'test()', 'id': 42, 'message': 'Third Message'}
-Test Log: {'sender': 'test()', 'id': 42, 'message': 'Third Message'}
-</code></pre>
-<p>The "filter" key is required:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;}}, []))
-'filter' is a required property
-&lt;BLANKLINE&gt;
-Failed validating 'required' in schema:
-    {'properties': {'filter': {'items': {'type': 'object'},
-                               'type': 'array'}},
-     'required': ['filter']}
-&lt;BLANKLINE&gt;
-On instance:
-    {'plugin': 'Log'}
-Configuration for 'Test Log' is not valid.
-</code></pre>
-<p>The "filter" key has to contain a list of message templates, i.e.,
-JSON objects:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Log&quot;: {&quot;plugin&quot;: &quot;Log&quot;,
-...                   &quot;filter&quot;: [42]}}, []))
-42 is not of type 'object'
-&lt;BLANKLINE&gt;
-Failed validating 'type' in schema['properties']['filter']['items']:
-    {'type': 'object'}
-&lt;BLANKLINE&gt;
-On instance['filter'][0]:
-    42
-Configuration for 'Test Log' is not valid.
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class Log(BasePlugin):
-    &#34;&#34;&#34;Log messages on stdout.
-
-    The &#34;filter&#34; configuration key gets a list of message templates defining
-    the messages that should be logged by the plugin instance.
-
-    In the following example the first and third message match the given
-    template and are logged by the instance &#34;Test Log&#34;, while the second
-    message does not match and is only logged by the test, but not by the
-    Log instance:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;,
-    ...                   &#34;filter&#34;: [{&#34;id&#34;: {&#34;const&#34;: 42}}]}},
-    ...     [{&#34;id&#34;: 42, &#34;message&#34;: &#34;Test Message&#34;},
-    ...      {&#34;id&#34;: 42.42, &#34;message&#34;: &#34;Second Message&#34;},
-    ...      {&#34;id&#34;: 42, &#34;message&#34;: &#34;Third Message&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Log&#39;, &#39;plugin&#39;: &#39;Log&#39;,
-             &#39;sends&#39;: [], &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}
-    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42.42, &#39;message&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}
-    Test Log: {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42, &#39;message&#39;: &#39;Third Message&#39;}
-
-    The &#34;filter&#34; key is required:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;}}, []))
-    &#39;filter&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;filter&#39;: {&#39;items&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                   &#39;type&#39;: &#39;array&#39;}},
-         &#39;required&#39;: [&#39;filter&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Log&#39;}
-    Configuration for &#39;Test Log&#39; is not valid.
-
-    The &#34;filter&#34; key has to contain a list of message templates, i.e.,
-    JSON objects:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Log&#34;: {&#34;plugin&#34;: &#34;Log&#34;,
-    ...                   &#34;filter&#34;: [42]}}, []))
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;filter&#39;][&#39;items&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;filter&#39;][0]:
-        42
-    Configuration for &#39;Test Log&#39; is not valid.
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;filter&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                             &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},
-                   &#39;required&#39;: [&#39;filter&#39;]}
-    &#34;&#34;&#34;Schema for Log plugin configuration.
-
-    Required configuration key:
-
-    - &#39;filter&#39;: list of message templates to be logged.
-    &#34;&#34;&#34;
-
-    async def log(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Log received message on stdout using own name as prefix.&#34;&#34;&#34;
-        print(f&#34;{self.name}: {message}&#34;)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.bus.register(self.name, &#39;Log&#39;, [], self.conf[&#39;filter&#39;], self.log)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.util.Log.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for Log plugin configuration.</p>
-<p>Required configuration key:</p>
-<ul>
-<li>'filter': list of message templates to be logged.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.util.Log.log"><code class="name flex">
-<span>async def <span class="ident">log</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Log received message on stdout using own name as prefix.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def log(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Log received message on stdout using own name as prefix.&#34;&#34;&#34;
-    print(f&#34;{self.name}: {message}&#34;)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Log.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    self.bus.register(self.name, &#39;Log&#39;, [], self.conf[&#39;filter&#39;], self.log)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Log.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.util.Init"><code class="flex name class">
-<span>class <span class="ident">Init</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Send list of messages on startup and on demand.</p>
-<p>The "messages" configuration key gets a list of messages to be sent on
-startup. The same list is sent in reaction to a message with
-"target": <name> and "command": "execute".</p>
-<p>In the example, the two configured messages are sent twice, once at
-startup and a second time in reaction to the "execute" command sent by
-the test:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,
-...                    &quot;messages&quot;: [{&quot;id&quot;: 42,
-...                                  &quot;content&quot;: &quot;Test Message&quot;},
-...                                 {&quot;id&quot;: 42.42,
-...                                  &quot;content&quot;: &quot;Second Message&quot;}]}},
-...     [{&quot;target&quot;: &quot;Test Init&quot;, &quot;command&quot;: &quot;execute&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Init', 'plugin': 'Init',
-         'sends': [{'id': {'const': 42},
-                    'content': {'const': 'Test Message'}},
-                   {'id': {'const': 42.42},
-                    'content': {'const': 'Second Message'}}],
-         'receives': [{'target': {'const': 'Test Init'},
-                       'command': {'const': 'execute'}}]}
-test(): {'sender': 'Test Init', 'id': 42, 'content': 'Test Message'}
-test(): {'sender': 'Test Init', 'id': 42.42, 'content': 'Second Message'}
-test(): {'sender': 'test()', 'target': 'Test Init', 'command': 'execute'}
-test(): {'sender': 'Test Init', 'id': 42, 'content': 'Test Message'}
-test(): {'sender': 'Test Init', 'id': 42.42, 'content': 'Second Message'}
-</code></pre>
-<p>The "messages" key is required:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;}}, []))
-'messages' is a required property
-&lt;BLANKLINE&gt;
-Failed validating 'required' in schema:
-    {'properties': {'messages': {'items': {'type': 'object'},
-                                 'type': 'array'}},
-     'required': ['messages']}
-&lt;BLANKLINE&gt;
-On instance:
-    {'plugin': 'Init'}
-Configuration for 'Test Init' is not valid.
-</code></pre>
-<p>The "messages" key has to contain a list of (partial) messages, i.e.,
-JSON objects:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Init&quot;: {&quot;plugin&quot;: &quot;Init&quot;,
-...                    &quot;messages&quot;: [42]}}, []))
-42 is not of type 'object'
-&lt;BLANKLINE&gt;
-Failed validating 'type' in schema['properties']['messages']['items']:
-    {'type': 'object'}
-&lt;BLANKLINE&gt;
-On instance['messages'][0]:
-    42
-Configuration for 'Test Init' is not valid.
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class Init(BasePlugin):
-    &#34;&#34;&#34;Send list of messages on startup and on demand.
-
-    The &#34;messages&#34; configuration key gets a list of messages to be sent on
-    startup. The same list is sent in reaction to a message with
-    &#34;target&#34;: &lt;name&gt; and &#34;command&#34;: &#34;execute&#34;.
-
-    In the example, the two configured messages are sent twice, once at
-    startup and a second time in reaction to the &#34;execute&#34; command sent by
-    the test:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-    ...                    &#34;messages&#34;: [{&#34;id&#34;: 42,
-    ...                                  &#34;content&#34;: &#34;Test Message&#34;},
-    ...                                 {&#34;id&#34;: 42.42,
-    ...                                  &#34;content&#34;: &#34;Second Message&#34;}]}},
-    ...     [{&#34;target&#34;: &#34;Test Init&#34;, &#34;command&#34;: &#34;execute&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Init&#39;, &#39;plugin&#39;: &#39;Init&#39;,
-             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Test Message&#39;}},
-                       {&#39;id&#39;: {&#39;const&#39;: 42.42},
-                        &#39;content&#39;: {&#39;const&#39;: &#39;Second Message&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Init&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Init&#39;, &#39;command&#39;: &#39;execute&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Init&#39;, &#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}
-
-    The &#34;messages&#34; key is required:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;}}, []))
-    &#39;messages&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;messages&#39;: {&#39;items&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                     &#39;type&#39;: &#39;array&#39;}},
-         &#39;required&#39;: [&#39;messages&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Init&#39;}
-    Configuration for &#39;Test Init&#39; is not valid.
-
-    The &#34;messages&#34; key has to contain a list of (partial) messages, i.e.,
-    JSON objects:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Init&#34;: {&#34;plugin&#34;: &#34;Init&#34;,
-    ...                    &#34;messages&#34;: [42]}}, []))
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;messages&#39;][&#39;items&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;messages&#39;][0]:
-        42
-    Configuration for &#39;Test Init&#39; is not valid.
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                               &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},
-                   &#39;required&#39;: [&#39;messages&#39;]}
-    &#34;&#34;&#34;Schema for Init plugin configuration.
-
-    Required configuration key:
-
-    - &#39;messages&#39;: list of messages to be sent.
-    &#34;&#34;&#34;
-
-    async def execute(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Send configured messages.&#34;&#34;&#34;
-        for message in self.conf[&#39;messages&#39;]:
-            await self.bus.send(Message(self.name, message))
-            # Give immediate reactions to messages opportunity to happen:
-            await asyncio.sleep(0)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}})]
-        sends = [MessageTemplate.from_message(message)
-                 for message in self.conf[&#39;messages&#39;]]
-        self.bus.register(self.name, &#39;Init&#39;, sends, receives, self.execute)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Send configured messages on startup.&#34;&#34;&#34;
-        for message in self.conf[&#39;messages&#39;]:
-            await self.bus.send(Message(self.name, message))</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.util.Init.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for Init plugin configuration.</p>
-<p>Required configuration key:</p>
-<ul>
-<li>'messages': list of messages to be sent.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.util.Init.execute"><code class="name flex">
-<span>async def <span class="ident">execute</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Send configured messages.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def execute(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Send configured messages.&#34;&#34;&#34;
-    for message in self.conf[&#39;messages&#39;]:
-        await self.bus.send(Message(self.name, message))
-        # Give immediate reactions to messages opportunity to happen:
-        await asyncio.sleep(0)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Init.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}})]
-    sends = [MessageTemplate.from_message(message)
-             for message in self.conf[&#39;messages&#39;]]
-    self.bus.register(self.name, &#39;Init&#39;, sends, receives, self.execute)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Init.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Send configured messages on startup.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Send configured messages on startup.&#34;&#34;&#34;
-    for message in self.conf[&#39;messages&#39;]:
-        await self.bus.send(Message(self.name, message))</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.util.Execute"><code class="flex name class">
-<span>class <span class="ident">Execute</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Send configurable list of messages on demand.</p>
-<p>An Execute plugin instance receives two kinds of commands.
-The "set messages" command has a "messages" key with a list of (partial)
-messages, which are sent by the Execute instance in reaction to an
-"execute" command.</p>
-<p>In the example, the first command sent by the test sets two messages,
-which are then sent in reaction to the second command sent by the test:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Execute&quot;: {&quot;plugin&quot;: &quot;Execute&quot;}},
-...     [{&quot;target&quot;: &quot;Test Execute&quot;, &quot;command&quot;: &quot;set messages&quot;,
-...       &quot;messages&quot;: [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;},
-...                    {&quot;id&quot;: 42.42, &quot;content&quot;: &quot;Second Message&quot;}]},
-...      {&quot;target&quot;: &quot;Test Execute&quot;, &quot;command&quot;: &quot;execute&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Execute', 'plugin': 'Execute',
-         'sends': [{}],
-         'receives': [{'target': {'const': 'Test Execute'},
-                       'command': {'const': 'set messages'},
-                       'messages': {'type': 'array',
-                                    'items': {'type': 'object'}}},
-                      {'target': {'const': 'Test Execute'},
-                       'command': {'const': 'execute'}}]}
-test(): {'sender': 'test()', 'target': 'Test Execute',
-         'command': 'set messages',
-         'messages': [{'id': 42, 'content': 'Test Message'},
-                      {'id': 42.42, 'content': 'Second Message'}]}
-test(): {'sender': 'test()', 'target': 'Test Execute',
-         'command': 'execute'}
-test(): {'sender': 'Test Execute', 'id': 42,
-         'content': 'Test Message'}
-test(): {'sender': 'Test Execute', 'id': 42.42,
-         'content': 'Second Message'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class Execute(BasePlugin):
-    &#34;&#34;&#34;Send configurable list of messages on demand.
-
-    An Execute plugin instance receives two kinds of commands.
-    The &#34;set messages&#34; command has a &#34;messages&#34; key with a list of (partial)
-    messages, which are sent by the Execute instance in reaction to an
-    &#34;execute&#34; command.
-
-    In the example, the first command sent by the test sets two messages,
-    which are then sent in reaction to the second command sent by the test:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Execute&#34;: {&#34;plugin&#34;: &#34;Execute&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test Execute&#34;, &#34;command&#34;: &#34;set messages&#34;,
-    ...       &#34;messages&#34;: [{&#34;id&#34;: 42, &#34;content&#34;: &#34;Test Message&#34;},
-    ...                    {&#34;id&#34;: 42.42, &#34;content&#34;: &#34;Second Message&#34;}]},
-    ...      {&#34;target&#34;: &#34;Test Execute&#34;, &#34;command&#34;: &#34;execute&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Execute&#39;, &#39;plugin&#39;: &#39;Execute&#39;,
-             &#39;sends&#39;: [{}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},
-                           &#39;messages&#39;: {&#39;type&#39;: &#39;array&#39;,
-                                        &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}},
-                          {&#39;target&#39;: {&#39;const&#39;: &#39;Test Execute&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,
-             &#39;command&#39;: &#39;set messages&#39;,
-             &#39;messages&#39;: [{&#39;id&#39;: 42, &#39;content&#39;: &#39;Test Message&#39;},
-                          {&#39;id&#39;: 42.42, &#39;content&#39;: &#39;Second Message&#39;}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Execute&#39;,
-             &#39;command&#39;: &#39;execute&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42,
-             &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Execute&#39;, &#39;id&#39;: 42.42,
-             &#39;content&#39;: &#39;Second Message&#39;}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = True
-    &#34;&#34;&#34;Schema for Execute plugin configuration.
-
-    There are no required or optional configuration keys.
-    &#34;&#34;&#34;
-
-    async def execute(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Set or send configured messages.&#34;&#34;&#34;
-        if message[&#39;command&#39;] == &#39;set messages&#39;:
-            assert isinstance(message[&#39;messages&#39;], list)
-            self.messages = list(message[&#39;messages&#39;])
-        elif message[&#39;command&#39;] == &#39;execute&#39;:
-            for message in self.messages:
-                await self.bus.send(Message(self.name, message))
-                # Give immediate reactions to messages opportunity to happen:
-                await asyncio.sleep(0)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.messages = []
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},
-                                     &#39;messages&#39;:
-                                     {&#39;type&#39;: &#39;array&#39;,
-                                      &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}}),
-                    MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}})]
-        sends = [MessageTemplate()]
-        self.bus.register(self.name, &#39;Execute&#39;, sends, receives, self.execute)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.util.Execute.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for Execute plugin configuration.</p>
-<p>There are no required or optional configuration keys.</p></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.util.Execute.execute"><code class="name flex">
-<span>async def <span class="ident">execute</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Set or send configured messages.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def execute(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Set or send configured messages.&#34;&#34;&#34;
-    if message[&#39;command&#39;] == &#39;set messages&#39;:
-        assert isinstance(message[&#39;messages&#39;], list)
-        self.messages = list(message[&#39;messages&#39;])
-    elif message[&#39;command&#39;] == &#39;execute&#39;:
-        for message in self.messages:
-            await self.bus.send(Message(self.name, message))
-            # Give immediate reactions to messages opportunity to happen:
-            await asyncio.sleep(0)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Execute.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    self.messages = []
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;set messages&#39;},
-                                 &#39;messages&#39;:
-                                 {&#39;type&#39;: &#39;array&#39;,
-                                  &#39;items&#39;: {&#39;type&#39;: &#39;object&#39;}}}),
-                MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;execute&#39;}})]
-    sends = [MessageTemplate()]
-    self.bus.register(self.name, &#39;Execute&#39;, sends, receives, self.execute)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Execute.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.util.Alias"><code class="flex name class">
-<span>class <span class="ident">Alias</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Translate messages to an alias.</p>
-<p>The "from" configuration key gets a message template and the
-configuration key "to" a (partial) message. All messages matching the
-template are received by the Alias instance and a message translated by
-removing the keys of the "from" template and adding the keys and values
-of the "to" message is sent. Keys that are neither in "from" nor in "to"
-are retained.</p>
-<p>In the example, the two messages sent by the test are translated by the
-Alias instance and the translated messages are sent by it preserving
-the "content" keys:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,
-...                     &quot;from&quot;: {&quot;id&quot;: {&quot;const&quot;: 42}},
-...                     &quot;to&quot;: {&quot;id&quot;: &quot;translated&quot;}}},
-...     [{&quot;id&quot;: 42, &quot;content&quot;: &quot;Test Message&quot;},
-...      {&quot;id&quot;: 42, &quot;content&quot;: &quot;Second Message&quot;}]))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Alias', 'plugin': 'Alias',
-         'sends': [{'id': {'const': 'translated'}}],
-         'receives': [{'id': {'const': 42}}]}
-test(): {'sender': 'test()', 'id': 42,
-         'content': 'Test Message'}
-test(): {'sender': 'Test Alias', 'id': 'translated',
-         'content': 'Test Message'}
-test(): {'sender': 'test()', 'id': 42,
-         'content': 'Second Message'}
-test(): {'sender': 'Test Alias', 'id': 'translated',
-         'content': 'Second Message'}
-</code></pre>
-<p>The "from" and "to" keys are required:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;}}, []))
-'from' is a required property
-&lt;BLANKLINE&gt;
-Failed validating 'required' in schema:
-    {'properties': {'from': {'type': 'object'}, 'to': {'type': 'object'}},
-     'required': ['from', 'to']}
-&lt;BLANKLINE&gt;
-On instance:
-    {'plugin': 'Alias'}
-'to' is a required property
-&lt;BLANKLINE&gt;
-Failed validating 'required' in schema:
-    {'properties': {'from': {'type': 'object'}, 'to': {'type': 'object'}},
-     'required': ['from', 'to']}
-&lt;BLANKLINE&gt;
-On instance:
-    {'plugin': 'Alias'}
-Configuration for 'Test Alias' is not valid.
-</code></pre>
-<p>The "from" key has to contain a message template and the "to" key a
-(partial) message, i.e., both have to be JSON objects:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Alias&quot;: {&quot;plugin&quot;: &quot;Alias&quot;,
-...                     &quot;from&quot;: 42,
-...                     &quot;to&quot;: 42}}, []))
-42 is not of type 'object'
-&lt;BLANKLINE&gt;
-Failed validating 'type' in schema['properties']['from']:
-    {'type': 'object'}
-&lt;BLANKLINE&gt;
-On instance['from']:
-    42
-42 is not of type 'object'
-&lt;BLANKLINE&gt;
-Failed validating 'type' in schema['properties']['to']:
-    {'type': 'object'}
-&lt;BLANKLINE&gt;
-On instance['to']:
-    42
-Configuration for 'Test Alias' is not valid.
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class Alias(BasePlugin):
-    &#34;&#34;&#34;Translate messages to an alias.
-
-    The &#34;from&#34; configuration key gets a message template and the
-    configuration key &#34;to&#34; a (partial) message. All messages matching the
-    template are received by the Alias instance and a message translated by
-    removing the keys of the &#34;from&#34; template and adding the keys and values
-    of the &#34;to&#34; message is sent. Keys that are neither in &#34;from&#34; nor in &#34;to&#34;
-    are retained.
-
-    In the example, the two messages sent by the test are translated by the
-    Alias instance and the translated messages are sent by it preserving
-    the &#34;content&#34; keys:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;,
-    ...                     &#34;from&#34;: {&#34;id&#34;: {&#34;const&#34;: 42}},
-    ...                     &#34;to&#34;: {&#34;id&#34;: &#34;translated&#34;}}},
-    ...     [{&#34;id&#34;: 42, &#34;content&#34;: &#34;Test Message&#34;},
-    ...      {&#34;id&#34;: 42, &#34;content&#34;: &#34;Second Message&#34;}]))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test Alias&#39;, &#39;plugin&#39;: &#39;Alias&#39;,
-             &#39;sends&#39;: [{&#39;id&#39;: {&#39;const&#39;: &#39;translated&#39;}}],
-             &#39;receives&#39;: [{&#39;id&#39;: {&#39;const&#39;: 42}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,
-             &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,
-             &#39;content&#39;: &#39;Test Message&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;id&#39;: 42,
-             &#39;content&#39;: &#39;Second Message&#39;}
-    test(): {&#39;sender&#39;: &#39;Test Alias&#39;, &#39;id&#39;: &#39;translated&#39;,
-             &#39;content&#39;: &#39;Second Message&#39;}
-
-    The &#34;from&#34; and &#34;to&#34; keys are required:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;}}, []))
-    &#39;from&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;}, &#39;to&#39;: {&#39;type&#39;: &#39;object&#39;}},
-         &#39;required&#39;: [&#39;from&#39;, &#39;to&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Alias&#39;}
-    &#39;to&#39; is a required property
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;required&#39; in schema:
-        {&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;}, &#39;to&#39;: {&#39;type&#39;: &#39;object&#39;}},
-         &#39;required&#39;: [&#39;from&#39;, &#39;to&#39;]}
-    &lt;BLANKLINE&gt;
-    On instance:
-        {&#39;plugin&#39;: &#39;Alias&#39;}
-    Configuration for &#39;Test Alias&#39; is not valid.
-
-    The &#34;from&#34; key has to contain a message template and the &#34;to&#34; key a
-    (partial) message, i.e., both have to be JSON objects:
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test Alias&#34;: {&#34;plugin&#34;: &#34;Alias&#34;,
-    ...                     &#34;from&#34;: 42,
-    ...                     &#34;to&#34;: 42}}, []))
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;from&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;from&#39;]:
-        42
-    42 is not of type &#39;object&#39;
-    &lt;BLANKLINE&gt;
-    Failed validating &#39;type&#39; in schema[&#39;properties&#39;][&#39;to&#39;]:
-        {&#39;type&#39;: &#39;object&#39;}
-    &lt;BLANKLINE&gt;
-    On instance[&#39;to&#39;]:
-        42
-    Configuration for &#39;Test Alias&#39; is not valid.
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;from&#39;: {&#39;type&#39;: &#39;object&#39;},
-                                  &#39;to&#39;: {&#39;type&#39;: &#39;object&#39;}},
-                   &#39;required&#39;: [&#39;from&#39;, &#39;to&#39;]}
-    &#34;&#34;&#34;Schema for Alias plugin configuration.
-
-    Required configuration keys:
-
-    - &#39;from&#39;: template of messages to be translated.
-    - &#39;to&#39;: translated message to be sent.
-    &#34;&#34;&#34;
-
-    async def alias(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Translate and send message.&#34;&#34;&#34;
-        alias_message = Message(self.name)
-        alias_message.update(self.conf[&#39;to&#39;])
-        for key in message:
-            if key != &#39;sender&#39; and key not in self.conf[&#39;from&#39;]:
-                alias_message[key] = message[key]
-        await self.bus.send(alias_message)
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        self.bus.register(self.name, &#39;Alias&#39;,
-                          [MessageTemplate.from_message(self.conf[&#39;to&#39;])],
-                          [self.conf[&#39;from&#39;]],
-                          self.alias)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.util.Alias.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for Alias plugin configuration.</p>
-<p>Required configuration keys:</p>
-<ul>
-<li>'from': template of messages to be translated.</li>
-<li>'to': translated message to be sent.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.util.Alias.alias"><code class="name flex">
-<span>async def <span class="ident">alias</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Translate and send message.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def alias(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Translate and send message.&#34;&#34;&#34;
-    alias_message = Message(self.name)
-    alias_message.update(self.conf[&#39;to&#39;])
-    for key in message:
-        if key != &#39;sender&#39; and key not in self.conf[&#39;from&#39;]:
-            alias_message[key] = message[key]
-    await self.bus.send(alias_message)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Alias.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    self.bus.register(self.name, &#39;Alias&#39;,
-                      [MessageTemplate.from_message(self.conf[&#39;to&#39;])],
-                      [self.conf[&#39;from&#39;]],
-                      self.alias)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.util.Alias.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-</dl>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3>Super-module</h3>
-<ul>
-<li><code><a title="controlpi_plugins" href="index.html">controlpi_plugins</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-classes">Classes</a></h3>
-<ul>
-<li>
-<h4><code><a title="controlpi_plugins.util.Log" href="#controlpi_plugins.util.Log">Log</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.util.Log.log" href="#controlpi_plugins.util.Log.log">log</a></code></li>
-<li><code><a title="controlpi_plugins.util.Log.process_conf" href="#controlpi_plugins.util.Log.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.util.Log.run" href="#controlpi_plugins.util.Log.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.util.Log.CONF_SCHEMA" href="#controlpi_plugins.util.Log.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.util.Init" href="#controlpi_plugins.util.Init">Init</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.util.Init.execute" href="#controlpi_plugins.util.Init.execute">execute</a></code></li>
-<li><code><a title="controlpi_plugins.util.Init.process_conf" href="#controlpi_plugins.util.Init.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.util.Init.run" href="#controlpi_plugins.util.Init.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.util.Init.CONF_SCHEMA" href="#controlpi_plugins.util.Init.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.util.Execute" href="#controlpi_plugins.util.Execute">Execute</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.util.Execute.execute" href="#controlpi_plugins.util.Execute.execute">execute</a></code></li>
-<li><code><a title="controlpi_plugins.util.Execute.process_conf" href="#controlpi_plugins.util.Execute.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.util.Execute.run" href="#controlpi_plugins.util.Execute.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.util.Execute.CONF_SCHEMA" href="#controlpi_plugins.util.Execute.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.util.Alias" href="#controlpi_plugins.util.Alias">Alias</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.util.Alias.alias" href="#controlpi_plugins.util.Alias.alias">alias</a></code></li>
-<li><code><a title="controlpi_plugins.util.Alias.process_conf" href="#controlpi_plugins.util.Alias.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.util.Alias.run" href="#controlpi_plugins.util.Alias.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.util.Alias.CONF_SCHEMA" href="#controlpi_plugins.util.Alias.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
diff --git a/doc/controlpi_plugins/wait.html b/doc/controlpi_plugins/wait.html
deleted file mode 100644 (file)
index a5230a5..0000000
+++ /dev/null
@@ -1,604 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
-<meta name="generator" content="pdoc 0.9.2" />
-<title>controlpi_plugins.wait API documentation</title>
-<meta name="description" content="Provide waiting/sleeping plugins for all kinds of systems …" />
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
-<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
-<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
-<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
-<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
-<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
-<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
-<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
-</head>
-<body>
-<main>
-<article id="content">
-<header>
-<h1 class="title">Module <code>controlpi_plugins.wait</code></h1>
-</header>
-<section id="section-intro">
-<p>Provide waiting/sleeping plugins for all kinds of systems.</p>
-<ul>
-<li>Wait waits for time defined in configuration and sends "finished" event.</li>
-<li>GenericWait waits for time defined in "wait" command and sends "finished"
-event with "id" string defined in "wait" command.</li>
-</ul>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.01},
-...      &quot;Test GenericWait&quot;: {&quot;plugin&quot;: &quot;GenericWait&quot;}},
-...     [{&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,
-...       &quot;seconds&quot;: 0.02, &quot;id&quot;: &quot;Long Wait&quot;},
-...      {&quot;target&quot;: &quot;Test Wait&quot;, &quot;command&quot;: &quot;wait&quot;}], 0.025))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test Wait', 'plugin': 'Wait',
-         'sends': [{'event': {'const': 'finished'}}],
-         'receives': [{'target': {'const': 'Test Wait'},
-                       'command': {'const': 'wait'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test GenericWait', 'plugin': 'GenericWait',
-         'sends': [{'event': {'const': 'finished'},
-                    'id': {'type': 'string'}}],
-         'receives': [{'target': {'const': 'Test GenericWait'},
-                       'command': {'const': 'wait'},
-                       'seconds': {'type': 'number'},
-                       'id': {'type': 'string'}}]}
-test(): {'sender': 'test()', 'target': 'Test GenericWait',
-         'command': 'wait', 'seconds': 0.02, 'id': 'Long Wait'}
-test(): {'sender': 'test()', 'target': 'Test Wait', 'command': 'wait'}
-test(): {'sender': 'Test Wait', 'event': 'finished'}
-test(): {'sender': 'Test GenericWait', 'event': 'finished',
-         'id': 'Long Wait'}
-</code></pre>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">&#34;&#34;&#34;Provide waiting/sleeping plugins for all kinds of systems.
-
-- Wait waits for time defined in configuration and sends &#34;finished&#34; event.
-- GenericWait waits for time defined in &#34;wait&#34; command and sends &#34;finished&#34;
-  event with &#34;id&#34; string defined in &#34;wait&#34; command.
-
-&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&#34;Test Wait&#34;: {&#34;plugin&#34;: &#34;Wait&#34;, &#34;seconds&#34;: 0.01},
-...      &#34;Test GenericWait&#34;: {&#34;plugin&#34;: &#34;GenericWait&#34;}},
-...     [{&#34;target&#34;: &#34;Test GenericWait&#34;, &#34;command&#34;: &#34;wait&#34;,
-...       &#34;seconds&#34;: 0.02, &#34;id&#34;: &#34;Long Wait&#34;},
-...      {&#34;target&#34;: &#34;Test Wait&#34;, &#34;command&#34;: &#34;wait&#34;}], 0.025))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test Wait&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}
-test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-         &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,
-         &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},
-                    &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-         &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},
-                       &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},
-                       &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},
-                       &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,
-         &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}
-test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test Wait&#39;, &#39;command&#39;: &#39;wait&#39;}
-test(): {&#39;sender&#39;: &#39;Test Wait&#39;, &#39;event&#39;: &#39;finished&#39;}
-test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,
-         &#39;id&#39;: &#39;Long Wait&#39;}
-&#34;&#34;&#34;
-import asyncio
-
-from controlpi import BasePlugin, Message, MessageTemplate
-
-
-class Wait(BasePlugin):
-    &#34;&#34;&#34;Wait for time defined in configuration.
-
-    The &#34;seconds&#34; configuration key gets the number of seconds to wait after
-    receiving a &#34;wait&#34; command before sending the &#34;finished&#34; event:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Long Wait&#34;: {&#34;plugin&#34;: &#34;Wait&#34;, &#34;seconds&#34;: 0.02},
-    ...      &#34;Short Wait&#34;: {&#34;plugin&#34;: &#34;Wait&#34;, &#34;seconds&#34;: 0.01}},
-    ...     [{&#34;target&#34;: &#34;Long Wait&#34;, &#34;command&#34;: &#34;wait&#34;},
-    ...      {&#34;target&#34;: &#34;Short Wait&#34;, &#34;command&#34;: &#34;wait&#34;}], 0.025))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Long Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Long Wait&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Short Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Short Wait&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Long Wait&#39;, &#39;command&#39;: &#39;wait&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Short Wait&#39;, &#39;command&#39;: &#39;wait&#39;}
-    test(): {&#39;sender&#39;: &#39;Short Wait&#39;, &#39;event&#39;: &#39;finished&#39;}
-    test(): {&#39;sender&#39;: &#39;Long Wait&#39;, &#39;event&#39;: &#39;finished&#39;}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;}},
-                   &#39;required&#39;: [&#39;seconds&#39;]}
-    &#34;&#34;&#34;Schema for Wait plugin configuration.
-
-    Required configuration key:
-
-    - &#39;seconds&#39;: number of seconds to wait.
-    &#34;&#34;&#34;
-
-    async def wait(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Wait configured time and send &#34;finished&#34; event.&#34;&#34;&#34;
-        async def wait_coroutine():
-            await asyncio.sleep(self.conf[&#39;seconds&#39;])
-            await self.bus.send(Message(self.name, {&#39;event&#39;: &#39;finished&#39;}))
-        # Done in separate task to not block queue awaiting this callback:
-        asyncio.create_task(wait_coroutine())
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}})]
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}})]
-        self.bus.register(self.name, &#39;Wait&#39;, sends, receives, self.wait)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass
-
-
-class GenericWait(BasePlugin):
-    &#34;&#34;&#34;Wait for time defined in &#34;wait&#34; command.
-
-    The &#34;wait&#34; command has message keys &#34;seconds&#34; defining the seconds to
-    wait and &#34;id&#34; defining a string to be sent back in the &#34;finished&#34; event
-    after the wait:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test GenericWait&#34;: {&#34;plugin&#34;: &#34;GenericWait&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test GenericWait&#34;, &#34;command&#34;: &#34;wait&#34;,
-    ...       &#34;seconds&#34;: 0.02, &#34;id&#34;: &#34;Long Wait&#34;},
-    ...      {&#34;target&#34;: &#34;Test GenericWait&#34;, &#34;command&#34;: &#34;wait&#34;,
-    ...       &#34;seconds&#34;: 0.01, &#34;id&#34;: &#34;Short Wait&#34;}], 0.025))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},
-                        &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},
-                           &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},
-                           &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,
-             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,
-             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.01, &#39;id&#39;: &#39;Short Wait&#39;}
-    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,
-             &#39;id&#39;: &#39;Short Wait&#39;}
-    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,
-             &#39;id&#39;: &#39;Long Wait&#39;}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = True
-    &#34;&#34;&#34;Schema for GenericWait plugin configuration.
-
-    There are no required or optional configuration keys.
-    &#34;&#34;&#34;
-
-    async def wait(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Wait given time and send &#34;finished&#34; event with given &#34;id&#34;.&#34;&#34;&#34;
-        async def wait_coroutine():
-            assert isinstance(message[&#39;seconds&#39;], float)
-            await asyncio.sleep(message[&#39;seconds&#39;])
-            await self.bus.send(Message(self.name, {&#39;event&#39;: &#39;finished&#39;,
-                                                    &#39;id&#39;: message[&#39;id&#39;]}))
-        # Done in separate task to not block queue awaiting this callback:
-        asyncio.create_task(wait_coroutine())
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},
-                                     &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                     &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}})]
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},
-                                  &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}})]
-        self.bus.register(self.name, &#39;GenericWait&#39;, sends, receives, self.wait)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-</section>
-<section>
-<h2 class="section-title" id="header-classes">Classes</h2>
-<dl>
-<dt id="controlpi_plugins.wait.Wait"><code class="flex name class">
-<span>class <span class="ident">Wait</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Wait for time defined in configuration.</p>
-<p>The "seconds" configuration key gets the number of seconds to wait after
-receiving a "wait" command before sending the "finished" event:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Long Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.02},
-...      &quot;Short Wait&quot;: {&quot;plugin&quot;: &quot;Wait&quot;, &quot;seconds&quot;: 0.01}},
-...     [{&quot;target&quot;: &quot;Long Wait&quot;, &quot;command&quot;: &quot;wait&quot;},
-...      {&quot;target&quot;: &quot;Short Wait&quot;, &quot;command&quot;: &quot;wait&quot;}], 0.025))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Long Wait', 'plugin': 'Wait',
-         'sends': [{'event': {'const': 'finished'}}],
-         'receives': [{'target': {'const': 'Long Wait'},
-                       'command': {'const': 'wait'}}]}
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Short Wait', 'plugin': 'Wait',
-         'sends': [{'event': {'const': 'finished'}}],
-         'receives': [{'target': {'const': 'Short Wait'},
-                       'command': {'const': 'wait'}}]}
-test(): {'sender': 'test()', 'target': 'Long Wait', 'command': 'wait'}
-test(): {'sender': 'test()', 'target': 'Short Wait', 'command': 'wait'}
-test(): {'sender': 'Short Wait', 'event': 'finished'}
-test(): {'sender': 'Long Wait', 'event': 'finished'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class Wait(BasePlugin):
-    &#34;&#34;&#34;Wait for time defined in configuration.
-
-    The &#34;seconds&#34; configuration key gets the number of seconds to wait after
-    receiving a &#34;wait&#34; command before sending the &#34;finished&#34; event:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Long Wait&#34;: {&#34;plugin&#34;: &#34;Wait&#34;, &#34;seconds&#34;: 0.02},
-    ...      &#34;Short Wait&#34;: {&#34;plugin&#34;: &#34;Wait&#34;, &#34;seconds&#34;: 0.01}},
-    ...     [{&#34;target&#34;: &#34;Long Wait&#34;, &#34;command&#34;: &#34;wait&#34;},
-    ...      {&#34;target&#34;: &#34;Short Wait&#34;, &#34;command&#34;: &#34;wait&#34;}], 0.025))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Long Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Long Wait&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Short Wait&#39;, &#39;plugin&#39;: &#39;Wait&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Short Wait&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Long Wait&#39;, &#39;command&#39;: &#39;wait&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Short Wait&#39;, &#39;command&#39;: &#39;wait&#39;}
-    test(): {&#39;sender&#39;: &#39;Short Wait&#39;, &#39;event&#39;: &#39;finished&#39;}
-    test(): {&#39;sender&#39;: &#39;Long Wait&#39;, &#39;event&#39;: &#39;finished&#39;}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = {&#39;properties&#39;: {&#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;}},
-                   &#39;required&#39;: [&#39;seconds&#39;]}
-    &#34;&#34;&#34;Schema for Wait plugin configuration.
-
-    Required configuration key:
-
-    - &#39;seconds&#39;: number of seconds to wait.
-    &#34;&#34;&#34;
-
-    async def wait(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Wait configured time and send &#34;finished&#34; event.&#34;&#34;&#34;
-        async def wait_coroutine():
-            await asyncio.sleep(self.conf[&#39;seconds&#39;])
-            await self.bus.send(Message(self.name, {&#39;event&#39;: &#39;finished&#39;}))
-        # Done in separate task to not block queue awaiting this callback:
-        asyncio.create_task(wait_coroutine())
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}})]
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}})]
-        self.bus.register(self.name, &#39;Wait&#39;, sends, receives, self.wait)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.wait.Wait.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for Wait plugin configuration.</p>
-<p>Required configuration key:</p>
-<ul>
-<li>'seconds': number of seconds to wait.</li>
-</ul></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.wait.Wait.wait"><code class="name flex">
-<span>async def <span class="ident">wait</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Wait configured time and send "finished" event.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def wait(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Wait configured time and send &#34;finished&#34; event.&#34;&#34;&#34;
-    async def wait_coroutine():
-        await asyncio.sleep(self.conf[&#39;seconds&#39;])
-        await self.bus.send(Message(self.name, {&#39;event&#39;: &#39;finished&#39;}))
-    # Done in separate task to not block queue awaiting this callback:
-    asyncio.create_task(wait_coroutine())</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.wait.Wait.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;}})]
-    sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;}})]
-    self.bus.register(self.name, &#39;Wait&#39;, sends, receives, self.wait)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.wait.Wait.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-<dt id="controlpi_plugins.wait.GenericWait"><code class="flex name class">
-<span>class <span class="ident">GenericWait</span></span>
-<span>(</span><span>bus: <a title="controlpi.messagebus.MessageBus" href="../controlpi/messagebus.html#controlpi.messagebus.MessageBus">MessageBus</a>, name: str, conf: Dict[str, Any])</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Wait for time defined in "wait" command.</p>
-<p>The "wait" command has message keys "seconds" defining the seconds to
-wait and "id" defining a string to be sent back in the "finished" event
-after the wait:</p>
-<pre><code class="language-python-repl">&gt;&gt;&gt; import controlpi
-&gt;&gt;&gt; asyncio.run(controlpi.test(
-...     {&quot;Test GenericWait&quot;: {&quot;plugin&quot;: &quot;GenericWait&quot;}},
-...     [{&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,
-...       &quot;seconds&quot;: 0.02, &quot;id&quot;: &quot;Long Wait&quot;},
-...      {&quot;target&quot;: &quot;Test GenericWait&quot;, &quot;command&quot;: &quot;wait&quot;,
-...       &quot;seconds&quot;: 0.01, &quot;id&quot;: &quot;Short Wait&quot;}], 0.025))
-... # doctest: +NORMALIZE_WHITESPACE
-test(): {'sender': '', 'event': 'registered',
-         'client': 'Test GenericWait', 'plugin': 'GenericWait',
-         'sends': [{'event': {'const': 'finished'},
-                    'id': {'type': 'string'}}],
-         'receives': [{'target': {'const': 'Test GenericWait'},
-                       'command': {'const': 'wait'},
-                       'seconds': {'type': 'number'},
-                       'id': {'type': 'string'}}]}
-test(): {'sender': 'test()', 'target': 'Test GenericWait',
-         'command': 'wait', 'seconds': 0.02, 'id': 'Long Wait'}
-test(): {'sender': 'test()', 'target': 'Test GenericWait',
-         'command': 'wait', 'seconds': 0.01, 'id': 'Short Wait'}
-test(): {'sender': 'Test GenericWait', 'event': 'finished',
-         'id': 'Short Wait'}
-test(): {'sender': 'Test GenericWait', 'event': 'finished',
-         'id': 'Long Wait'}
-</code></pre></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">class GenericWait(BasePlugin):
-    &#34;&#34;&#34;Wait for time defined in &#34;wait&#34; command.
-
-    The &#34;wait&#34; command has message keys &#34;seconds&#34; defining the seconds to
-    wait and &#34;id&#34; defining a string to be sent back in the &#34;finished&#34; event
-    after the wait:
-    &gt;&gt;&gt; import controlpi
-    &gt;&gt;&gt; asyncio.run(controlpi.test(
-    ...     {&#34;Test GenericWait&#34;: {&#34;plugin&#34;: &#34;GenericWait&#34;}},
-    ...     [{&#34;target&#34;: &#34;Test GenericWait&#34;, &#34;command&#34;: &#34;wait&#34;,
-    ...       &#34;seconds&#34;: 0.02, &#34;id&#34;: &#34;Long Wait&#34;},
-    ...      {&#34;target&#34;: &#34;Test GenericWait&#34;, &#34;command&#34;: &#34;wait&#34;,
-    ...       &#34;seconds&#34;: 0.01, &#34;id&#34;: &#34;Short Wait&#34;}], 0.025))
-    ... # doctest: +NORMALIZE_WHITESPACE
-    test(): {&#39;sender&#39;: &#39;&#39;, &#39;event&#39;: &#39;registered&#39;,
-             &#39;client&#39;: &#39;Test GenericWait&#39;, &#39;plugin&#39;: &#39;GenericWait&#39;,
-             &#39;sends&#39;: [{&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},
-                        &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}],
-             &#39;receives&#39;: [{&#39;target&#39;: {&#39;const&#39;: &#39;Test GenericWait&#39;},
-                           &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},
-                           &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},
-                           &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}}]}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,
-             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.02, &#39;id&#39;: &#39;Long Wait&#39;}
-    test(): {&#39;sender&#39;: &#39;test()&#39;, &#39;target&#39;: &#39;Test GenericWait&#39;,
-             &#39;command&#39;: &#39;wait&#39;, &#39;seconds&#39;: 0.01, &#39;id&#39;: &#39;Short Wait&#39;}
-    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,
-             &#39;id&#39;: &#39;Short Wait&#39;}
-    test(): {&#39;sender&#39;: &#39;Test GenericWait&#39;, &#39;event&#39;: &#39;finished&#39;,
-             &#39;id&#39;: &#39;Long Wait&#39;}
-    &#34;&#34;&#34;
-
-    CONF_SCHEMA = True
-    &#34;&#34;&#34;Schema for GenericWait plugin configuration.
-
-    There are no required or optional configuration keys.
-    &#34;&#34;&#34;
-
-    async def wait(self, message: Message) -&gt; None:
-        &#34;&#34;&#34;Wait given time and send &#34;finished&#34; event with given &#34;id&#34;.&#34;&#34;&#34;
-        async def wait_coroutine():
-            assert isinstance(message[&#39;seconds&#39;], float)
-            await asyncio.sleep(message[&#39;seconds&#39;])
-            await self.bus.send(Message(self.name, {&#39;event&#39;: &#39;finished&#39;,
-                                                    &#39;id&#39;: message[&#39;id&#39;]}))
-        # Done in separate task to not block queue awaiting this callback:
-        asyncio.create_task(wait_coroutine())
-
-    def process_conf(self) -&gt; None:
-        &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-        receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                     &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},
-                                     &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                     &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}})]
-        sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},
-                                  &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}})]
-        self.bus.register(self.name, &#39;GenericWait&#39;, sends, receives, self.wait)
-
-    async def run(self) -&gt; None:
-        &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-        pass</code></pre>
-</details>
-<h3>Ancestors</h3>
-<ul class="hlist">
-<li><a title="controlpi.baseplugin.BasePlugin" href="../controlpi/baseplugin.html#controlpi.baseplugin.BasePlugin">BasePlugin</a></li>
-<li>abc.ABC</li>
-</ul>
-<h3>Class variables</h3>
-<dl>
-<dt id="controlpi_plugins.wait.GenericWait.CONF_SCHEMA"><code class="name">var <span class="ident">CONF_SCHEMA</span></code></dt>
-<dd>
-<div class="desc"><p>Schema for GenericWait plugin configuration.</p>
-<p>There are no required or optional configuration keys.</p></div>
-</dd>
-</dl>
-<h3>Methods</h3>
-<dl>
-<dt id="controlpi_plugins.wait.GenericWait.wait"><code class="name flex">
-<span>async def <span class="ident">wait</span></span>(<span>self, message: <a title="controlpi.messagebus.Message" href="../controlpi/messagebus.html#controlpi.messagebus.Message">Message</a>) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Wait given time and send "finished" event with given "id".</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def wait(self, message: Message) -&gt; None:
-    &#34;&#34;&#34;Wait given time and send &#34;finished&#34; event with given &#34;id&#34;.&#34;&#34;&#34;
-    async def wait_coroutine():
-        assert isinstance(message[&#39;seconds&#39;], float)
-        await asyncio.sleep(message[&#39;seconds&#39;])
-        await self.bus.send(Message(self.name, {&#39;event&#39;: &#39;finished&#39;,
-                                                &#39;id&#39;: message[&#39;id&#39;]}))
-    # Done in separate task to not block queue awaiting this callback:
-    asyncio.create_task(wait_coroutine())</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.wait.GenericWait.process_conf"><code class="name flex">
-<span>def <span class="ident">process_conf</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Register plugin as bus client.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">def process_conf(self) -&gt; None:
-    &#34;&#34;&#34;Register plugin as bus client.&#34;&#34;&#34;
-    receives = [MessageTemplate({&#39;target&#39;: {&#39;const&#39;: self.name},
-                                 &#39;command&#39;: {&#39;const&#39;: &#39;wait&#39;},
-                                 &#39;seconds&#39;: {&#39;type&#39;: &#39;number&#39;},
-                                 &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}})]
-    sends = [MessageTemplate({&#39;event&#39;: {&#39;const&#39;: &#39;finished&#39;},
-                              &#39;id&#39;: {&#39;type&#39;: &#39;string&#39;}})]
-    self.bus.register(self.name, &#39;GenericWait&#39;, sends, receives, self.wait)</code></pre>
-</details>
-</dd>
-<dt id="controlpi_plugins.wait.GenericWait.run"><code class="name flex">
-<span>async def <span class="ident">run</span></span>(<span>self) ‑> NoneType</span>
-</code></dt>
-<dd>
-<div class="desc"><p>Run no code proactively.</p></div>
-<details class="source">
-<summary>
-<span>Expand source code</span>
-</summary>
-<pre><code class="python">async def run(self) -&gt; None:
-    &#34;&#34;&#34;Run no code proactively.&#34;&#34;&#34;
-    pass</code></pre>
-</details>
-</dd>
-</dl>
-</dd>
-</dl>
-</section>
-</article>
-<nav id="sidebar">
-<h1>Index</h1>
-<div class="toc">
-<ul></ul>
-</div>
-<ul id="index">
-<li><h3>Super-module</h3>
-<ul>
-<li><code><a title="controlpi_plugins" href="index.html">controlpi_plugins</a></code></li>
-</ul>
-</li>
-<li><h3><a href="#header-classes">Classes</a></h3>
-<ul>
-<li>
-<h4><code><a title="controlpi_plugins.wait.Wait" href="#controlpi_plugins.wait.Wait">Wait</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.wait.Wait.wait" href="#controlpi_plugins.wait.Wait.wait">wait</a></code></li>
-<li><code><a title="controlpi_plugins.wait.Wait.process_conf" href="#controlpi_plugins.wait.Wait.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.wait.Wait.run" href="#controlpi_plugins.wait.Wait.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.wait.Wait.CONF_SCHEMA" href="#controlpi_plugins.wait.Wait.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-<li>
-<h4><code><a title="controlpi_plugins.wait.GenericWait" href="#controlpi_plugins.wait.GenericWait">GenericWait</a></code></h4>
-<ul class="">
-<li><code><a title="controlpi_plugins.wait.GenericWait.wait" href="#controlpi_plugins.wait.GenericWait.wait">wait</a></code></li>
-<li><code><a title="controlpi_plugins.wait.GenericWait.process_conf" href="#controlpi_plugins.wait.GenericWait.process_conf">process_conf</a></code></li>
-<li><code><a title="controlpi_plugins.wait.GenericWait.run" href="#controlpi_plugins.wait.GenericWait.run">run</a></code></li>
-<li><code><a title="controlpi_plugins.wait.GenericWait.CONF_SCHEMA" href="#controlpi_plugins.wait.GenericWait.CONF_SCHEMA">CONF_SCHEMA</a></code></li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-</nav>
-</main>
-<footer id="footer">
-<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
-</footer>
-</body>
-</html>
\ No newline at end of file
index d67a64e99096a3fe8c9c1683b4676c5110f88eb6..faa0e12b73bfcaaaf1c5e563ae96eb3226141b75 100644 (file)
@@ -25,9 +25,9 @@ Die ControlPi-Infrastruktur hat zwei Haupt-Bestandteile:
   Dictionaries bzw. Mappings.)
 
 Die generierte Dokumentation des API der grundlegenden Infrastruktur ist
-unter [controlpi/](graphit/controlpi/controlpi/) zu finden.
+unter [api/controlpi/](graphit/controlpi/api/controlpi/) zu finden.
 Die Kollektion an grundlegenden Plugins ist unter
-[controlpi_plugins/](graphit/controlpi/controlpi_plugins/) dokumentiert.
+[api/controlpi_plugins/](graphit/controlpi/api/controlpi_plugins/) dokumentiert.
 
 Um Nachrichten zu senden und/oder zu empfangen muss ein Klient am Bus unter
 einem Namen registriert werden.
@@ -481,24 +481,10 @@ editierbar installiert werden:
 ```
 
 ## Code-Stil, Typ-Checks und Tests
-Die Formatierung des Codes und das Vorhandensein und der Stil der
-Kommentare werden durch
-[`pycodestyle`](https://pycodestyle.pycqa.org/en/latest/) und
-[`pydocstyle`](http://www.pydocstyle.org/en/stable/) überprüft.
-Die an Funktionen und Variablen annotierten Typ-Informationen werden durch
-[`mypy`](http://mypy-lang.org/) gecheckt.
-Alle drei Tools können rekursiv ein gesamtes Python-Paket überprüfen:
-```sh
-(venv)$ pycodestyle <Pfad zum Code-Repository>/controlpi
-(venv)$ pydocstyle <Pfad zum Code-Repository>/controlpi
-(venv)$ mypy <Pfad zum Code-Repository>/controlpi
-```
-
-Sie sind als Extra-Requirements in der Datei `setup.py` definiert, sodass
-sie mit einem einzigen `pip`-Aufruf installiert werden können:
-```sh
-(venv)$ pip install --editable <Pfad zum Code-Repository>[dev]
-```
+Die Formatierung des Codes und das Vorhandensein und der Stil der Kommentare
+werden durch [`ruff`](https://docs.astral.sh/ruff/) und die an Funktionen und
+Variablen annotierten Typ-Informationen werden durch
+[`ty`](https://docs.astral.sh/ty/) überprüft.
 
 Der Code wird durch in die Dokumentation eingebettete „doctests“ getestet.
 Diese können für jede Code-Datei einzeln mit dem in der
@@ -517,14 +503,10 @@ des Codes mit Tests erhält man mit der zusätzlichen Option `-v`:
 (venv)$ python -m doctest -v <Pfad zur Code-Datei>
 ```
 
-Außerdem wird durch die `[dev]`-Extras in `setup.py` auch das Tool
-[`pdoc`](https://pdoc3.github.io/pdoc/) zur automatischen Generierung von
-API-Dokumentation in HTML installiert:
+Außerdem wird das Tool
+[`pdoc`](https://pdoc.dev/docs/pdoc.html) zur automatischen Generierung von
+API-Dokumentation in HTML benutzt:
 ```sh
-(venv)$ pdoc --html --config sort_identifiers=False --force \
-             --output-dir doc/ controlpi/ controlpi_plugins/
+(venv)$ pdoc -o doc/api/ controlpi controlpi_plugins
 ```
-Mit diesem wurden auch die oben verlinkten API-Dokumentationen für
-[`controlpi`](graphit/controlpi/controlpi/) und
-[`controlpi_plugins`](graphit/controlpi/controlpi_plugins/)
-generiert.
+Mit diesem wurden auch die oben verlinkten API-Dokumentationen generiert.
index 275a14cefcee9f0e339419f69899afdf58143ac2..47bed5dc766a6689b23a99086481da63da678bce 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -19,14 +19,6 @@ setuptools.setup(
         "fastjsonschema",
         "pyinotify",
     ],
-    extras_require={
-        "dev": [
-            "pycodestyle",
-            "pydocstyle",
-            "mypy",
-            "pdoc3",
-        ]
-    },
     classifiers=[
         "Programming Language :: Python",
         "License :: OSI Approved :: MIT License",