



Graphene-Python@import url("https://fonts.googleapis.com/css?family=Fira+Mono|Open+Sans:400,600");.nonexisting[data-jsx="3652023954"]{content:""}.graphene-header[data-jsx="3652023954"]{background:#000000;width:100%;font-family:"klavika-web";font-weight:300;font-size:18px;color:#ffffff;-webkit-letter-spacing:0;-moz-letter-spacing:0;-ms-letter-spacing:0;letter-spacing:0}#menu[data-jsx="3652023954"]{position:absolute;top:0}.graphene-logo{vertical-align:middle}.graphene-header[data-jsx="3652023954"] .container[data-jsx="3652023954"]{height:48px;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.tagline[data-jsx="3652023954"]{margin-left:auto;color:#a4b1b2;font-size:14px;-webkit-letter-spacing:0;-moz-letter-spacing:0;-ms-letter-spacing:0;letter-spacing:0;margin-bottom:0;margin-top:0;text-transform:none;font-weight:normal}.tagline[data-jsx="3652023954"] b[data-jsx="3652023954"]{font-weight:400;-webkit-letter-spacing:0.3px;-moz-letter-spacing:0.3px;-ms-letter-spacing:0.3px;letter-spacing:0.3px;color:white}svg.arrow{margin-left:8px;position:relative;top:2px}#search-docs{padding:5px 5px 5px 29px;margin-top:-2px;vertical-align:middle;font-size:14px;width:180px;background:transparent;border:none;background-image:url("/search.svg");background-size:16px 16px;background-repeat:no-repeat;background-position-y:center;background-position-x:5px;border-bottom:1px solid rgba(0,0,0,0.1)}.background-mobile-menu[data-jsx="3652023954"]{position:fixed;z-index:9999;background:rgba(200,200,200,0.3);top:0;bottom:0;right:0;left:0;display:none}.mobile-menu[data-jsx="3652023954"]{display:none;color:black}#search-docs:focus{outline:none;border-bottom-color:rgba(0,0,0,0.6)}.navbar-header-contrast[data-jsx="3652023954"] #search-docs{background-image:url("https://graphene-python.org/search-white.svg");color:white;border-bottom-color:rgba(255,255,255,0.5)}.navbar-header-contrast[data-jsx="3652023954"] #search-docs:focus{border-bottom-color:#ffffff}.navbar-header-contrast[data-jsx="3652023954"] #search-docs::-webkit-input-placeholder{color:rgba(255,255,255,0.6)}.navbar-header-contrast[data-jsx="3652023954"] #search-docs::-moz-placeholder{color:rgba(255,255,255,0.6)}.navbar-header-contrast[data-jsx="3652023954"] #search-docs:-ms-input-placeholder{color:rgba(255,255,255,0.6)}.navbar-header-contrast[data-jsx="3652023954"] #search-docs::placeholder{color:rgba(255,255,255,0.6)}.navbar-header-contrast[data-jsx="3652023954"]{background-image:linear-gradient( -180deg, #f67049 0%, #e14b2e 100% )}.navbar-header[data-jsx="3652023954"]{height:94px}.navbar-header[data-jsx="3652023954"] .container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:94px}.navbar-header[data-jsx="3652023954"] nav[data-jsx="3652023954"]{height:100%;display:block;margin-left:auto}.nav-link{height:100%;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#555555;font-size:13px;font-family:"Open Sans",sans-serif;font-weight:600;height:94px;line-height:94px;padding:0 10px;margin:0;text-decoration:none;font-weight:600;position:relative}@media (max-width:992px){#search-docs{width:120px}}.nav-link-active{color:black}.nav-link-active:before{position:absolute;content:"";bottom:-10px;width:4px;height:4px;left:50%;margin-left:-2px;border-radius:2px;background:black}.navbar-header-contrast[data-jsx="3652023954"] .nav-link-active:before{background:white}.nav-link:hover{color:black}.navbar-header-contrast[data-jsx="3652023954"] .nav-link{color:white}.navbar-header-contrast[data-jsx="3652023954"] .nav-link:hover{color:#eee}@media (max-width:768px){#search-docs{display:none}.mobile-menu[data-jsx="3652023954"]{display:block;position:absolute;right:20px;font-size:20px}.navbar-header-contrast[data-jsx="3652023954"] .mobile-menu[data-jsx="3652023954"]{color:white}.tagline[data-jsx="3652023954"] .hide-mobile[data-jsx="3652023954"]{display:none}.navbar-header[data-jsx="3652023954"] nav[data-jsx="3652023954"]{height:auto;color:black;position:fixed;top:0;bottom:0;right:0;width:280px;display:block;background:white;z-index:10000;-webkit-transform:translateX(305px);-ms-transform:translateX(305px);transform:translateX(305px);box-shadow:0px 2px 25px rgba(0,0,0,0.15);-webkit-transition:all 0.5s cubic-bezier(0.55,0,0.1,1);transition:all 0.5s cubic-bezier(0.55,0,0.1,1)}.navbar-header-contrast[data-jsx="3652023954"] .nav-link{color:black}.navbar-header-contrast[data-jsx="3652023954"] .nav-link:hover{color:#333}.mobile-menu[data-jsx="3652023954"]{display:block}#menu[data-jsx="3652023954"]:target~.background-mobile-menu[data-jsx="3652023954"]{display:block;cursor:default}#menu[data-jsx="3652023954"]:target~nav[data-jsx="3652023954"]{-webkit-transform:translateX(0px);-ms-transform:translateX(0px);transform:translateX(0px)}.navbar-header[data-jsx="3652023954"] .nav-link{height:auto;display:block;width:100%;text-align:center;padding:0;margin:18px 0;line-height:20px}}.nonexisting[data-jsx="3652023954"]{content:""}

/\*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9sYXlvdXRzL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXdIb0IsQUFHaUMsQUFHRCxBQVVELEFBSUksQUFLVixBQUtLLEFBVUQsQUFNQSxBQUtTLEFBZVYsQUFVRixBQUlBLEFBSXdELEFBS3pDLEFBR0csQUFPOUIsQUFJVyxBQUdDLEFBTUQsQUFLQSxBQWdCRSxBQUlGLEFBR00sQUFXRCxBQUdMLEFBR0EsQUFHRCxBQUtJLEFBR0MsQUFNRixBQUdDLEFBR0QsQUFlQSxBQUdELEFBR0csQUFHQSxBQUlZLEFBR2QsQUFVa0UsQUFFekQsV0E5RHpCLEFBc0NFLENBN0ttQixBQThFckIsQUFTZ0IsQUFLSyxBQWdCbkIsQUFJRixBQWlCQSxBQUdBLEFBaUJFLEFBTWMsQUFlZCxBQWdCZ0IsQ0F2SUosQUFJMkIsQUFxRnZDLEFBWUEsQ0FUb0IsQUFpQ3BCLEFBR2lCLENBMUlKLENBMUJRLEFBTUgsQ0FoQkosQUF5SGhCLENBdklRLEFBNEhLLENBdElBLENBSGIsRUFpQkEsQ0EyTUEsQ0E5TUEsQUFvS21CLENBbElELEFBMEJsQixDQW9DbUIsQUFtR0osRUFqSnVCLEFBc0J0QyxBQUdBLENBaURlLEFBZ0ViLENBck0wQixDQXVCWCxDQTBJRixFQTFITCxHQXNLWSxFQS9CWixFQWxJYyxDQUp4QixBQThGWSxDQTVCWixBQXdEbUIsRUFhTixDQXZKTSxHQWlEbkIsR0E4RGEsRUF5Q0QsQ0E4QkUsQ0E3TUksRUFrS2hCLEdBdkdNLENBcUhRLENBcElDLEFBMkZOLEVBdUVPLEVBbEpQLEVBZUcsQ0FlZCxFQXpGaUIsQUF1SUUsRUF2Q0UsQUFnRkgsRUFwSFIsRUFoQkksQ0FrS08sRUFuSTBCLEdBZHRDLEdBNURPLENBZ0xLLENBekNELENBM0ZLLEFBeUp2QixDQXhJYSxLQWlKYixLQTdNaUIsR0E2RG5CLENBL0NlLEFBNEZDLEFBc0VFLEVBekNDLE1BM0ZMLElBZkEsRUE4RUcsQUFzRWUsSUF2R2hDLENBOERBLENBM0ZzQyxJQWZ0QyxFQVRrQixHQXVGb0IsYUF0RnZCLGFBQ08sQ0F1Qk0sTUFpRGQsRUFjSSxVQTlGbEIsQUFpRkEsQ0F4RXFCLEtBc0ZQLENBN0dkLENBOEM4QixVQWdFWCxFQXRGbkIsZUF1RmlCLENBaEVjLEFBa0lpQixjQWpFckMsU0FDWSxNQWpFSyxZQWtJMEIsR0FoRXBDLFdBakUyQixLQWtFekIsa0JBQ3BCLGlCQWxFQSxnREFpSUUiLCJmaWxlIjoic3JjL2xheW91dHMvaW5kZXguanMiLCJzb3VyY2VSb290IjoiL29wdC9idWlsZC9yZXBvIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tIFwicHJvcC10eXBlc1wiO1xuaW1wb3J0IExpbmsgZnJvbSBcImdhdHNieS1saW5rXCI7XG5pbXBvcnQgSGVsbWV0IGZyb20gXCJyZWFjdC1oZWxtZXRcIjtcbmltcG9ydCBHcmFwaGVuZUxvZ28gZnJvbSBcIi4vZ3JhcGhlbmUtbG9nby5zdmdcIjtcbmltcG9ydCBBcnJvdyBmcm9tIFwiLi9hcnJvdy5zdmdcIjtcbmltcG9ydCBMb2dvT25XaGl0ZSBmcm9tIFwiLi9sb2dvLW9uLXdoaXRlLnN2Z1wiO1xuaW1wb3J0IEdyYXBoZW5lTG9nb1doaXRlIGZyb20gXCIuL2dyYXBoZW5lLWxvZ28td2hpdGUuc3ZnXCI7XG5pbXBvcnQgeyBGYUdpdGh1YiwgRmFCYXJzIH0gZnJvbSBcInJlYWN0LWljb25zL2ZhXCI7XG5cbmltcG9ydCBcImRvY3NlYXJjaC5qcy9kaXN0L2Nkbi9kb2NzZWFyY2gubWluLmNzc1wiO1xuaW1wb3J0IFwiLi9pbmRleC5jc3NcIjtcblxuY29uc3QgU0VBUkNIX0RPQ1MgPSB0cnVlO1xuXG4vLyBsZXQgZG9jc2VhcmNoO1xuLy8gaWYgKHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIgJiYgU0VBUkNIX0RPQ1MpIHtcbi8vICAgZG9jc2VhcmNoID0gcmVxdWlyZShcImRvY3NlYXJjaC5qcy9kaXN0L2Nkbi9kb2NzZWFyY2gubWluXCIpO1xuLy8gICB0cnkge1xuLy8gICAgIGRvY3NlYXJjaCh7XG4vLyAgICAgICBhcGlLZXk6IFwiNGI2ZDBhZmE4MDE5N2RiMzU4ODY1NTViNWVmNDcyMWZcIixcbi8vICAgICAgIGlucHV0U2VsZWN0b3I6IFwiI3NlYXJjaC1kb2NzXCIsXG4vLyAgICAgICBpbmRleE5hbWU6IFwiZ3JhcGhlbmVfcHl0aG9uXCIsXG4vLyAgICAgICB0cmFuc2Zvcm1EYXRhOiBmdW5jdGlvbihzdWdnZXN0aW9ucykge1xuLy8gICAgICAgICByZXR1cm4gc3VnZ2VzdGlvbnMubWFwKGZ1bmN0aW9uKHN1Z2dlc3Rpb24pIHtcbi8vICAgICAgICAgICBzdWdnZXN0aW9uLnVybC5yZXBsYWNlKFwiaHR0cDpcIiwgXCJodHRwczpcIik7XG4vLyAgICAgICAgICAgcmV0dXJuIHN1Z2dlc3Rpb247XG4vLyAgICAgICAgIH0pO1xuLy8gICAgICAgfSxcbi8vICAgICAgIC8vIFwic3RhcnRfdXJsc1wiOiBbXCJodHRwczovL3d3dy5leGFtcGxlLmNvbS9kb2NzXCJdLFxuLy8gICAgICAgZGVidWc6IGZhbHNlXG4vLyAgICAgfSk7XG4vLyAgIH0gY2F0Y2ggKGUpIHt9XG4vLyB9IGVsc2Uge1xuLy8gICBkb2NzZWFyY2ggPSBmYWxzZTtcbi8vIH1cblxuY29uc3QgSGVhZGVyTGluayA9ICh7IHRvLCBjaGlsZHJlbiwgZG9jcywgLi4uZXh0cmEgfSkgPT4ge1xuICBpZiAoZG9jcykge1xuICAgIHJldHVybiAoXG4gICAgICA8YSBocmVmPXtgaHR0cHM6Ly9ncmFwaGVuZS1weXRob24ub3JnJHt0b31gfSB7Li4uZXh0cmF9PlxuICAgICAgICB7Y2hpbGRyZW59XG4gICAgICA8L2E+XG4gICAgKTtcbiAgfVxuICByZXR1cm4gKFxuICAgIDxMaW5rIHRvPXt0b30gey4uLmV4dHJhfT5cbiAgICAgIHtjaGlsZHJlbn1cbiAgICA8L0xpbms+XG4gICk7XG59O1xuXG5jbGFzcyBIZWFkZXIgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICB0cnkge1xuICAgICAgaWYgKFNFQVJDSF9ET0NTICYmIHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgbGV0IGRvY3NlYXJjaCA9IHJlcXVpcmUoXCJkb2NzZWFyY2guanMvZGlzdC9jZG4vZG9jc2VhcmNoLm1pblwiKTtcbiAgICAgICAgZG9jc2VhcmNoKHtcbiAgICAgICAgICBhcGlLZXk6IFwiNGI2ZDBhZmE4MDE5N2RiMzU4ODY1NTViNWVmNDcyMWZcIixcbiAgICAgICAgICBpbnB1dFNlbGVjdG9yOiBcIiNzZWFyY2gtZG9jc1wiLFxuICAgICAgICAgIGluZGV4TmFtZTogXCJncmFwaGVuZV9weXRob25cIixcbiAgICAgICAgICB0cmFuc2Zvcm1EYXRhOiBmdW5jdGlvbihzdWdnZXN0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHN1Z2dlc3Rpb25zLm1hcChmdW5jdGlvbihzdWdnZXN0aW9uKSB7XG4gICAgICAgICAgICAgIHN1Z2dlc3Rpb24udXJsID0gc3VnZ2VzdGlvbi51cmwucmVwbGFjZShcImh0dHA6XCIsIFwiaHR0cHM6XCIpO1xuICAgICAgICAgICAgICByZXR1cm4gc3VnZ2VzdGlvbjtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBkZWJ1ZzogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7fVxuICB9XG4gIHJlbmRlcigpIHtcbiAgICBsZXQgeyBkb2NzIH0gPSB0aGlzLnByb3BzO1xuICAgIHJldHVybiAoXG4gICAgICA8ZGl2PlxuICAgICAgICA8aGVhZGVyXG4gICAgICAgICAgY2xhc3NOYW1lPXtgbmF2YmFyLWhlYWRlciAgJHtkb2NzID8gXCJuYXZiYXItaGVhZGVyLWNvbnRyYXN0XCIgOiBcIlwifWB9XG4gICAgICAgID5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImNvbnRhaW5lclwiPlxuICAgICAgICAgICAgPEhlYWRlckxpbmsgdG89XCIvXCIgY2xhc3NOYW1lPVwibG9nby1saW5rXCI+XG4gICAgICAgICAgICAgIHtkb2NzID8gPEdyYXBoZW5lTG9nb1doaXRlIC8+IDogPExvZ29PbldoaXRlIC8+fVxuICAgICAgICAgICAgPC9IZWFkZXJMaW5rPlxuICAgICAgICAgICAgPGEgaWQ9XCJtZW51XCIgLz5cbiAgICAgICAgICAgIDxhIGhyZWY9XCIjbWVudVwiIGNsYXNzTmFtZT1cIm1vYmlsZS1tZW51XCI+XG4gICAgICAgICAgICAgIDxGYUJhcnMgLz5cbiAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgIDxhIGNsYXNzTmFtZT1cImJhY2tncm91bmQtbW9iaWxlLW1lbnVcIiBocmVmPVwiI1wiIC8+XG4gICAgICAgICAgICA8bmF2PlxuICAgICAgICAgICAgICB7U0VBUkNIX0RPQ1MgPyAoXG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICBpZD1cInNlYXJjaC1kb2NzXCJcbiAgICAgICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiU2VhcmNoIHRoZSBkb2NzLi4uXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICApIDogbnVsbH1cbiAgICAgICAgICAgICAgPGFcbiAgICAgICAgICAgICAgICBocmVmPVwiaHR0cHM6Ly9kb2NzLmdyYXBoZW5lLXB5dGhvbi5vcmcvXCJcbiAgICAgICAgICAgICAgICBjbGFzc05hbWU9e2BuYXYtbGluayAke2RvY3MgPyBcIm5hdi1saW5rLWFjdGl2ZVwiIDogXCJcIn1gfVxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgRG9jdW1lbnRhdGlvblxuICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgIDxIZWFkZXJMaW5rXG4gICAgICAgICAgICAgICAgdG89XCIvdGVhbVwiXG4gICAgICAgICAgICAgICAgZG9jcz17ZG9jc31cbiAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJuYXYtbGlua1wiXG4gICAgICAgICAgICAgICAgYWN0aXZlQ2xhc3NOYW1lPVwibmF2LWxpbmstYWN0aXZlXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIFRlYW1cbiAgICAgICAgICAgICAgPC9IZWFkZXJMaW5rPlxuICAgICAgICAgICAgICA8YVxuICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm5hdi1saW5rXCJcbiAgICAgICAgICAgICAgICBocmVmPVwiaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtcHl0aG9uL2dyYXBoZW5lXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxGYUdpdGh1YiAvPiBHaXRodWJcbiAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgPC9uYXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvaGVhZGVyPlxuXG4gICAgICAgIDxzdHlsZSBqc3g+e2BcbiAgICAgICAgICAubm9uZXhpc3Rpbmcge1xuICAgICAgICAgICAgY29udGVudDogXCJ7JSByYXcgJX1cIjtcbiAgICAgICAgICB9XG4gICAgICAgICAgLmdyYXBoZW5lLWhlYWRlciB7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kOiAjMDAwMDAwO1xuICAgICAgICAgICAgd2lkdGg6IDEwMCU7XG4gICAgICAgICAgICAvKiBHcmFwaGVuZTogKi9cbiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBcImtsYXZpa2Etd2ViXCI7XG4gICAgICAgICAgICBmb250LXdlaWdodDogMzAwO1xuICAgICAgICAgICAgZm9udC1zaXplOiAxOHB4O1xuICAgICAgICAgICAgY29sb3I6ICNmZmZmZmY7XG4gICAgICAgICAgICBsZXR0ZXItc3BhY2luZzogMDtcbiAgICAgICAgICB9XG4gICAgICAgICAgI21lbnUge1xuICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICAgICAgdG9wOiAwO1xuICAgICAgICAgIH1cbiAgICAgICAgICA6Z2xvYmFsKC5ncmFwaGVuZS1sb2dvKSB7XG4gICAgICAgICAgICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuICAgICAgICAgIH1cbiAgICAgICAgICAuZ3JhcGhlbmUtaGVhZGVyIHtcbiAgICAgICAgICB9XG4gICAgICAgICAgLmdyYXBoZW5lLWhlYWRlciAuY29udGFpbmVyIHtcbiAgICAgICAgICAgIGhlaWdodDogNDhweDtcbiAgICAgICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICAgIH1cbiAgICAgICAgICAudGFnbGluZSB7XG4gICAgICAgICAgICBtYXJnaW4tbGVmdDogYXV0bztcbiAgICAgICAgICAgIGNvbG9yOiAjYTRiMWIyO1xuICAgICAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICAgICAgbGV0dGVyLXNwYWNpbmc6IDA7XG4gICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAwO1xuICAgICAgICAgICAgbWFyZ2luLXRvcDogMDtcbiAgICAgICAgICAgIHRleHQtdHJhbnNmb3JtOiBub25lO1xuICAgICAgICAgICAgZm9udC13ZWlnaHQ6IG5vcm1hbDtcbiAgICAgICAgICB9XG4gICAgICAgICAgLnRhZ2xpbmUgYiB7XG4gICAgICAgICAgICBmb250LXdlaWdodDogNDAwO1xuICAgICAgICAgICAgbGV0dGVyLXNwYWNpbmc6IDAuM3B4O1xuICAgICAgICAgICAgY29sb3I6IHdoaXRlO1xuICAgICAgICAgIH1cbiAgICAgICAgICA6Z2xvYmFsKHN2Zy5hcnJvdykge1xuICAgICAgICAgICAgLyp2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlOyovXG4gICAgICAgICAgICBtYXJnaW4tbGVmdDogOHB4O1xuICAgICAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgICAgICAgdG9wOiAycHg7XG4gICAgICAgICAgfVxuICAgICAgICAgIDpnbG9iYWwoI3NlYXJjaC1kb2NzKSB7XG4gICAgICAgICAgICBwYWRkaW5nOiA1cHggNXB4IDVweCAyOXB4O1xuICAgICAgICAgICAgbWFyZ2luLXRvcDogLTJweDtcbiAgICAgICAgICAgIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XG4gICAgICAgICAgICBmb250LXNpemU6IDE0cHg7XG4gICAgICAgICAgICB3aWR0aDogMTgwcHg7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICAgICAgICAgIGJvcmRlcjogbm9uZTtcbiAgICAgICAgICAgIGJhY2tncm91bmQtaW1hZ2U6IHVybChcIi9zZWFyY2guc3ZnXCIpO1xuICAgICAgICAgICAgYmFja2dyb3VuZC1zaXplOiAxNnB4IDE2cHg7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xuICAgICAgICAgICAgYmFja2dyb3VuZC1wb3NpdGlvbi15OiBjZW50ZXI7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uLXg6IDVweDtcbiAgICAgICAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCByZ2JhKDAsIDAsIDAsIDAuMSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC5iYWNrZ3JvdW5kLW1vYmlsZS1tZW51IHtcbiAgICAgICAgICAgIHBvc2l0aW9uOiBmaXhlZDtcbiAgICAgICAgICAgIHotaW5kZXg6IDk5OTk7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kOiByZ2JhKDIwMCwgMjAwLCAyMDAsIDAuMyk7XG4gICAgICAgICAgICB0b3A6IDA7XG4gICAgICAgICAgICBib3R0b206IDA7XG4gICAgICAgICAgICByaWdodDogMDtcbiAgICAgICAgICAgIGxlZnQ6IDA7XG4gICAgICAgICAgICBkaXNwbGF5OiBub25lO1xuICAgICAgICAgIH1cbiAgICAgICAgICAubW9iaWxlLW1lbnUge1xuICAgICAgICAgICAgZGlzcGxheTogbm9uZTtcbiAgICAgICAgICAgIGNvbG9yOiBibGFjaztcbiAgICAgICAgICB9XG4gICAgICAgICAgOmdsb2JhbCgjc2VhcmNoLWRvY3MpOmZvY3VzIHtcbiAgICAgICAgICAgIG91dGxpbmU6IG5vbmU7XG4gICAgICAgICAgICBib3JkZXItYm90dG9tLWNvbG9yOiByZ2JhKDAsIDAsIDAsIDAuNik7XG4gICAgICAgICAgfVxuICAgICAgICAgIC5uYXZiYXItaGVhZGVyLWNvbnRyYXN0IDpnbG9iYWwoI3NlYXJjaC1kb2NzKSB7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCJodHRwczovL2dyYXBoZW5lLXB5dGhvbi5vcmcvc2VhcmNoLXdoaXRlLnN2Z1wiKTtcbiAgICAgICAgICAgIGNvbG9yOiB3aGl0ZTtcbiAgICAgICAgICAgIGJvcmRlci1ib3R0b20tY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC41KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLm5hdmJhci1oZWFkZXItY29udHJhc3QgOmdsb2JhbCgjc2VhcmNoLWRvY3MpOmZvY3VzIHtcbiAgICAgICAgICAgIGJvcmRlci1ib3R0b20tY29sb3I6ICNmZmZmZmY7XG4gICAgICAgICAgfVxuICAgICAgICAgIC5uYXZiYXItaGVhZGVyLWNvbnRyYXN0IDpnbG9iYWwoI3NlYXJjaC1kb2NzKTo6cGxhY2Vob2xkZXIge1xuICAgICAgICAgICAgY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC42KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLm5hdmJhci1oZWFkZXItY29udHJhc3Qge1xuICAgICAgICAgICAgYmFja2dyb3VuZC1pbWFnZTogbGluZWFyLWdyYWRpZW50KFxuICAgICAgICAgICAgICAtMTgwZGVnLFxuICAgICAgICAgICAgICAjZjY3MDQ5IDAlLFxuICAgICAgICAgICAgICAjZTE0YjJlIDEwMCVcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLm5hdmJhci1oZWFkZXIge1xuICAgICAgICAgICAgaGVpZ2h0OiA5NHB4O1xuICAgICAgICAgIH1cbiAgICAgICAgICAubmF2YmFyLWhlYWRlciA6Z2xvYmFsKC5jb250YWluZXIpIHtcbiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgICAgICAgICAgaGVpZ2h0OiA5NHB4O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC5uYXZiYXItaGVhZGVyIG5hdiB7XG4gICAgICAgICAgICBoZWlnaHQ6IDEwMCU7XG4gICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgICAgIG1hcmdpbi1sZWZ0OiBhdXRvO1xuICAgICAgICAgIH1cbiAgICAgICAgICA6Z2xvYmFsKC5uYXYtbGluaykge1xuICAgICAgICAgICAgaGVpZ2h0OiAxMDAlO1xuICAgICAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgICAgICAgIGNvbG9yOiAjNTU1NTU1O1xuICAgICAgICAgICAgZm9udC1zaXplOiAxM3B4O1xuICAgICAgICAgICAgZm9udC1mYW1pbHk6IFwiT3BlbiBTYW5zXCIsIHNhbnMtc2VyaWY7XG4gICAgICAgICAgICBmb250LXdlaWdodDogNjAwO1xuICAgICAgICAgICAgaGVpZ2h0OiA5NHB4O1xuICAgICAgICAgICAgbGluZS1oZWlnaHQ6IDk0cHg7XG4gICAgICAgICAgICBwYWRkaW5nOiAwIDEwcHg7XG4gICAgICAgICAgICBtYXJnaW46IDA7XG4gICAgICAgICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG4gICAgICAgICAgICBmb250LXdlaWdodDogNjAwO1xuICAgICAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogOTkycHgpIHtcbiAgICAgICAgICAgIDpnbG9iYWwoI3NlYXJjaC1kb2NzKSB7XG4gICAgICAgICAgICAgIHdpZHRoOiAxMjBweDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgOmdsb2JhbCgubmF2LWxpbmstYWN0aXZlKSB7XG4gICAgICAgICAgICBjb2xvcjogYmxhY2s7XG4gICAgICAgICAgfVxuICAgICAgICAgIDpnbG9iYWwoLm5hdi1saW5rLWFjdGl2ZSk6YmVmb3JlIHtcbiAgICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgICAgIGNvbnRlbnQ6IFwiXCI7XG4gICAgICAgICAgICBib3R0b206IC0xMHB4O1xuICAgICAgICAgICAgd2lkdGg6IDRweDtcbiAgICAgICAgICAgIGhlaWdodDogNHB4O1xuICAgICAgICAgICAgbGVmdDogNTAlO1xuICAgICAgICAgICAgbWFyZ2luLWxlZnQ6IC0ycHg7XG4gICAgICAgICAgICBib3JkZXItcmFkaXVzOiAycHg7XG4gICAgICAgICAgICBiYWNrZ3JvdW5kOiBibGFjaztcbiAgICAgICAgICB9XG4gICAgICAgICAgLm5hdmJhci1oZWFkZXItY29udHJhc3QgOmdsb2JhbCgubmF2LWxpbmstYWN0aXZlKTpiZWZvcmUge1xuICAgICAgICAgICAgYmFja2dyb3VuZDogd2hpdGU7XG4gICAgICAgICAgfVxuICAgICAgICAgIDpnbG9iYWwoLm5hdi1saW5rKTpob3ZlciB7XG4gICAgICAgICAgICBjb2xvcjogYmxhY2s7XG4gICAgICAgICAgfVxuICAgICAgICAgIC5uYXZiYXItaGVhZGVyLWNvbnRyYXN0IDpnbG9iYWwoLm5hdi1saW5rKSB7XG4gICAgICAgICAgICBjb2xvcjogd2hpdGU7XG4gICAgICAgICAgfVxuICAgICAgICAgIC5uYXZiYXItaGVhZGVyLWNvbnRyYXN0IDpnbG9iYWwoLm5hdi1saW5rKTpob3ZlciB7XG4gICAgICAgICAgICBjb2xvcjogI2VlZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogNzY4cHgpIHtcbiAgICAgICAgICAgIDpnbG9iYWwoI3NlYXJjaC1kb2NzKSB7XG4gICAgICAgICAgICAgIGRpc3BsYXk6IG5vbmU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAubW9iaWxlLW1lbnUge1xuICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICAgICAgICByaWdodDogMjBweDtcbiAgICAgICAgICAgICAgZm9udC1zaXplOiAyMHB4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLm5hdmJhci1oZWFkZXItY29udHJhc3QgLm1vYmlsZS1tZW51IHtcbiAgICAgICAgICAgICAgY29sb3I6IHdoaXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLnRhZ2xpbmUgLmhpZGUtbW9iaWxlIHtcbiAgICAgICAgICAgICAgZGlzcGxheTogbm9uZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC5uYXZiYXItaGVhZGVyIG5hdiB7XG4gICAgICAgICAgICAgIGhlaWdodDogYXV0bztcbiAgICAgICAgICAgICAgY29sb3I6IGJsYWNrO1xuICAgICAgICAgICAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgICAgICAgICAgIHRvcDogMDtcbiAgICAgICAgICAgICAgYm90dG9tOiAwO1xuICAgICAgICAgICAgICByaWdodDogMDtcbiAgICAgICAgICAgICAgd2lkdGg6IDI4MHB4O1xuICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgICAgICAgYmFja2dyb3VuZDogd2hpdGU7XG4gICAgICAgICAgICAgIHotaW5kZXg6IDEwMDAwO1xuICAgICAgICAgICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoMzA1cHgpO1xuICAgICAgICAgICAgICBib3gtc2hhZG93OiAwcHggMnB4IDI1cHggcmdiYSgwLCAwLCAwLCAwLjE1KTtcbiAgICAgICAgICAgICAgdHJhbnNpdGlvbjogYWxsIDAuNXMgY3ViaWMtYmV6aWVyKDAuNTUsIDAsIDAuMSwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAubmF2YmFyLWhlYWRlci1jb250cmFzdCA6Z2xvYmFsKC5uYXYtbGluaykge1xuICAgICAgICAgICAgICBjb2xvcjogYmxhY2s7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAubmF2YmFyLWhlYWRlci1jb250cmFzdCA6Z2xvYmFsKC5uYXYtbGluayk6aG92ZXIge1xuICAgICAgICAgICAgICBjb2xvcjogIzMzMztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC5tb2JpbGUtbWVudSB7XG4gICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgI21lbnU6dGFyZ2V0IH4gLmJhY2tncm91bmQtbW9iaWxlLW1lbnUge1xuICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgICAgICAgY3Vyc29yOiBkZWZhdWx0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgI21lbnU6dGFyZ2V0IH4gbmF2IHtcbiAgICAgICAgICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVYKDBweCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAubmF2YmFyLWhlYWRlciA6Z2xvYmFsKC5uYXYtbGluaykge1xuICAgICAgICAgICAgICBoZWlnaHQ6IGF1dG87XG4gICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICAgICAgICB3aWR0aDogMTAwJTtcbiAgICAgICAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICAgICAgICBwYWRkaW5nOiAwO1xuICAgICAgICAgICAgICBtYXJnaW46IDE4cHggMDtcbiAgICAgICAgICAgICAgbGluZS1oZWlnaHQ6IDIwcHg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgQGltcG9ydCB1cmwoXCJodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tL2Nzcz9mYW1pbHk9RmlyYStNb25vfE9wZW4rU2Fuczo0MDAsNjAwXCIpO1xuICAgICAgICAgIC5ub25leGlzdGluZyB7XG4gICAgICAgICAgICBjb250ZW50OiBcInslIGVuZHJhdyAlfVwiO1xuICAgICAgICAgIH1cbiAgICAgICAgYH08L3N0eWxlPlxuICAgICAgICA8c2NyaXB0XG4gICAgICAgICAgdHlwZT1cInRleHQvamF2YXNjcmlwdFwiXG4gICAgICAgICAgZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUw9e3tcbiAgICAgICAgICAgIF9faHRtbDogYFxuICAgICAgICAgICAgZG9jc2VhcmNoKHtcbiAgICAgICAgICAgICAgYXBpS2V5OiBcIjRiNmQwYWZhODAxOTdkYjM1ODg2NTU1YjVlZjQ3MjFmXCIsXG4gICAgICAgICAgICAgIGlucHV0U2VsZWN0b3I6IFwiI3NlYXJjaC1kb2NzXCIsXG4gICAgICAgICAgICAgIGluZGV4TmFtZTogXCJncmFwaGVuZV9weXRob25cIixcbiAgICAgICAgICAgICAgdHJhbnNmb3JtRGF0YTogZnVuY3Rpb24oc3VnZ2VzdGlvbnMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3VnZ2VzdGlvbnMubWFwKGZ1bmN0aW9uKHN1Z2dlc3Rpb24pIHtcbiAgICAgICAgICAgICAgICAgIHN1Z2dlc3Rpb24udXJsID0gc3VnZ2VzdGlvbi51cmwucmVwbGFjZShcImh0dHA6XCIsIFwiaHR0cHM6XCIpO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHN1Z2dlc3Rpb247XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO2BcbiAgICAgICAgICB9fVxuICAgICAgICAvPlxuICAgICAgPC9kaXY+XG4gICAgKTtcbiAgfVxufVxuXG5jb25zdCBUZW1wbGF0ZVdyYXBwZXIgPSAoeyBjaGlsZHJlbiwgLi4ub3RoZXJQcm9wcyB9KSA9PiB7XG4gIGNvbnN0IGRvY3MgPSBvdGhlclByb3BzLmxvY2F0aW9uLnBhdGhuYW1lLmluZGV4T2YoXCIvZG9jc1wiKSA+IC0xO1xuICByZXR1cm4gKFxuICAgIDxkaXY+XG4gICAgICA8SGVsbWV0XG4gICAgICAgIHRpdGxlPVwiR3JhcGhlbmUtUHl0aG9uXCJcbiAgICAgICAgbWV0YT17W1xuICAgICAgICAgIHsgbmFtZTogXCJkZXNjcmlwdGlvblwiLCBjb250ZW50OiBcIkdyYXBoZW5lIGZyYW1ld29yayBmb3IgUHl0aG9uXCIgfSxcbiAgICAgICAgICB7IG5hbWU6IFwia2V5d29yZHNcIiwgY29udGVudDogXCJncmFwaGVuZSwgZ3JhcGhxbCwgcHl0aG9uLCBmcmFtZXdvcmtcIiB9XG4gICAgICAgIF19XG4gICAgICA+XG4gICAgICAgIDxzY3JpcHQgc3JjPVwiaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9kb2NzZWFyY2guanNAMi9kaXN0L2Nkbi9kb2NzZWFyY2gubWluLmpzXCIgLz5cbiAgICAgICAgey8qPHNjcmlwdD5cbiAgICAgICAgICB7YFxuICAgICAgZG9jc2VhcmNoKHtcbiAgICAgICAgYXBpS2V5OiBcIjRiNmQwYWZhODAxOTdkYjM1ODg2NTU1YjVlZjQ3MjFmXCIsXG4gICAgICAgIGlucHV0U2VsZWN0b3I6IFwiI3NlYXJjaC1kb2NzXCIsXG4gICAgICAgIGluZGV4TmFtZTogXCJncmFwaGVuZV9weXRob25cIixcbiAgICAgICAgdHJhbnNmb3JtRGF0YTogZnVuY3Rpb24oc3VnZ2VzdGlvbnMpIHtcbiAgICAgICAgICByZXR1cm4gc3VnZ2VzdGlvbnMubWFwKGZ1bmN0aW9uKHN1Z2dlc3Rpb24pIHtcbiAgICAgICAgICAgIHN1Z2dlc3Rpb24udXJsID0gc3VnZ2VzdGlvbi51cmwucmVwbGFjZShcImh0dHA6XCIsIFwiaHR0cHM6XCIpO1xuICAgICAgICAgICAgcmV0dXJuIHN1Z2dlc3Rpb247XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO2B9XG4gICAgPC9zY3JpcHQ+Ki99XG4gICAgICA8L0hlbG1ldD5cbiAgICAgIDxIZWFkZXIgZG9jcz17ZG9jc30gLz5cbiAgICAgIDxkaXY+e2NoaWxkcmVuKCl9PC9kaXY+XG4gICAgPC9kaXY+XG4gICk7XG59O1xuXG5UZW1wbGF0ZVdyYXBwZXIucHJvcFR5cGVzID0ge1xuICBjaGlsZHJlbjogUHJvcFR5cGVzLmZ1bmNcbn07XG5cbmV4cG9ydCBkZWZhdWx0IFRlbXBsYXRlV3JhcHBlcjtcbiJdfQ== \*/

/\*@ sourceURL=src/layouts/index.js \*/.docs-container{margin-top:54px;display:flex;margin-bottom:80px;color:#333}p{line-height:1.5}.callout a{color:#fff}.docs-side-nav{width:25%;margin-right:40px;min-width:200px;max-width:260px}.docs-main{flex:1}.sphinxsidebarwrapper ul{list-style:none;margin:0;padding:0}.sphinxsidebarwrapperlinks{margin-top:24px}.sphinxsidebarwrapperlinks a{font-size:16px;letter-spacing:0;color:#333}.sphinxsidebarwrapperlinks a.current{font-weight:700;color:#e14b2e}.documentwrapper h1,.documentwrapper h2,.documentwrapper h3,.documentwrapper h4,.documentwrapper h5{font-weight:500}.documentwrapper h1{font-size:36px}.documentwrapper h2{font-size:30px}.documentwrapper h3{font-size:26px}.documentwrapper h4{font-size:22px}.headerlink{display:none}.documentwrapper h1:hover .headerlink,.documentwrapper h2:hover .headerlink,.documentwrapper h3:hover .headerlink,.documentwrapper h4:hover .headerlink,.documentwrapper h5:hover .headerlink{margin-left:8px;display:inline}.go-buttons{margin-top:60px}.go-buttons .go-previous{float:left}.go-buttons .go-next{float:right}.sphinxsidebar li{padding:6px 0}.sphinxsidebar ul{list-style:none}.sphinxsidebar ul>li{font-size:15px;color:#e14b2e;letter-spacing:.2px}.sphinxsidebar ul>li>ul{margin-top:10px;border-left:2px solid #999;padding-left:16px}.sphinxsidebar ul>li>ul>li{font-size:14px;font-weight:400;color:#343434}.sphinxsidebar .toctree-l1>a{font-weight:400}.sphinxsidebar .sphinxsidebarwrapper li.current>a{color:#e14b2e;font-weight:500}.sphinxsidebar .sphinxsidebarwrapper li.current a:hover{color:#e14b2e}.sphinxsidebar .sphinxsidebarwrapper li.current>ul{border-left:2px solid #e14b2e}.wy-breadcrumbs{list-style:none}.wy-breadcrumbs li{display:inline-block;margin-right:5px;color:#606060}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px;color:#606060}.wy-breadcrumbs li a:first-child{padding-left:0}.rst-content .wy-breadcrumbs li tt,.wy-breadcrumbs li .rst-content tt,.wy-breadcrumbs li code{padding:5px;border:none;background:none}.fa-github,.rst-content .wy-breadcrumbs li tt.literal,.wy-breadcrumbs li .rst-content tt.literal,.wy-breadcrumbs li code.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}.section ul,.toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.section ul li,.toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.section ul li p:last-child,.section ul li ul,.toctree-wrapper ul li p:last-child,.toctree-wrapper ul li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.section ul li li,.toctree-wrapper ul li li,article ul li li{list-style:circle}.section ul li li li,.toctree-wrapper ul li li li,article ul li li li{list-style:square}.section ul li ol li,.toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.highlight .hll{background-color:#49483e}.code{box-sizing:border-box;max-width:100%;white-space:pre}pre{font-size:16px}.docutils.literal{border:1px solid #666;background:#eee;padding:3px 6px;border-radius:2px}.highlight{background:#272822;color:#f8f8f2;padding:8px 16px}.highlight pre{white-space:pre;overflow-x:auto}.highlight .c{color:#75715e}.highlight .err{color:#960050;background-color:#1e0010}.highlight .k{color:#66d9ef}.highlight .l{color:#ae81ff}.highlight .n{color:#f8f8f2}.highlight .o{color:#f92672}.highlight .p{color:#f8f8f2}.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cp,.highlight .cpf,.highlight .cs{color:#75715e}.highlight .gd{color:#f92672}.highlight .ge{font-style:italic}.highlight .gi{color:#a6e22e}.highlight .gs{font-weight:700}.highlight .gu{color:#75715e}.highlight .kc,.highlight .kd{color:#66d9ef}.highlight .kn{color:#f92672}.highlight .kp,.highlight .kr,.highlight .kt{color:#66d9ef}.highlight .ld{color:#e6db74}.highlight .m{color:#ae81ff}.highlight .s{color:#e6db74}.highlight .na{color:#a6e22e}.highlight .nb{color:#f8f8f2}.highlight .nc{color:#a6e22e}.highlight .no{color:#66d9ef}.highlight .nd{color:#a6e22e}.highlight .ni{color:#f8f8f2}.highlight .ne,.highlight .nf{color:#a6e22e}.highlight .nl,.highlight .nn{color:#f8f8f2}.highlight .nx{color:#a6e22e}.highlight .py{color:#f8f8f2}.highlight .nt{color:#f92672}.highlight .nv{color:#f8f8f2}.highlight .ow{color:#f92672}.highlight .w{color:#f8f8f2}.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:#ae81ff}.highlight .dl,.highlight .s2,.highlight .sa,.highlight .sb,.highlight .sc,.highlight .sd{color:#e6db74}.highlight .se{color:#ae81ff}.highlight .s1,.highlight .sh,.highlight .si,.highlight .sr,.highlight .ss,.highlight .sx{color:#e6db74}.highlight .bp{color:#f8f8f2}.highlight .fm{color:#a6e22e}.highlight .vc,.highlight .vg,.highlight .vi,.highlight .vm{color:#f8f8f2}.highlight .il{color:#ae81ff}.searchbox{display:inline-block;position:relative;width:200px;height:32px!important;white-space:nowrap;box-sizing:border-box;visibility:visible!important}.searchbox .algolia-autocomplete{display:block;width:100%;height:100%}.searchbox\_\_wrapper{width:100%;height:100%;z-index:1;position:relative}.searchbox\_\_input{display:inline-block;box-sizing:border-box;transition:box-shadow .4s ease,background .4s ease;border:0;border-radius:16px;box-shadow:inset 0 0 0 1px #ccc;background:#fff!important;padding:0;padding-right:26px;padding-left:32px;width:100%;height:100%;vertical-align:middle;white-space:normal;font-size:12px;-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbox\_\_input::-webkit-search-cancel-button,.searchbox\_\_input::-webkit-search-decoration,.searchbox\_\_input::-webkit-search-results-button,.searchbox\_\_input::-webkit-search-results-decoration{display:none}.searchbox\_\_input:hover{box-shadow:inset 0 0 0 1px #b3b3b3}.searchbox\_\_input:active,.searchbox\_\_input:focus{outline:0;box-shadow:inset 0 0 0 1px #aaa;background:#fff}.searchbox\_\_input::-webkit-input-placeholder{color:#aaa}.searchbox\_\_input:-ms-input-placeholder,.searchbox\_\_input::-ms-input-placeholder{color:#aaa}.searchbox\_\_input::placeholder{color:#aaa}.searchbox\_\_submit{position:absolute;top:0;margin:0;border:0;border-radius:16px 0 0 16px;background-color:rgba(69,142,225,0);padding:0;width:32px;height:100%;vertical-align:middle;text-align:center;font-size:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;right:inherit;left:0}.searchbox\_\_submit:before{display:inline-block;margin-right:-4px;height:100%;vertical-align:middle;content:""}.searchbox\_\_submit:active,.searchbox\_\_submit:hover{cursor:pointer}.searchbox\_\_submit:focus{outline:0}.searchbox\_\_submit svg{width:14px;height:14px;vertical-align:middle;fill:#6d7e96}.searchbox\_\_reset{display:block;position:absolute;top:8px;right:8px;margin:0;border:0;background:none;cursor:pointer;padding:0;font-size:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;fill:rgba(0,0,0,.5)}.searchbox\_\_reset.hide{display:none}.searchbox\_\_reset:focus{outline:0}.searchbox\_\_reset svg{display:block;margin:4px;width:8px;height:8px}.searchbox\_\_input:valid~.searchbox\_\_reset{display:block;-webkit-animation-name:a;animation-name:a;-webkit-animation-duration:.15s;animation-duration:.15s}@-webkit-keyframes a{0%{-webkit-transform:translate3d(-20%,0,0);transform:translate3d(-20%,0,0);opacity:0}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes a{0%{-webkit-transform:translate3d(-20%,0,0);transform:translate3d(-20%,0,0);opacity:0}to{-webkit-transform:none;transform:none;opacity:1}}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu{right:0!important;left:inherit!important}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before{right:48px}.algolia-autocomplete.algolia-autocomplete-left .ds-dropdown-menu{left:0!important;right:inherit!important}.algolia-autocomplete.algolia-autocomplete-left .ds-dropdown-menu:before{left:48px}.algolia-autocomplete .ds-dropdown-menu{top:-6px;border-radius:4px;margin:6px 0 0;padding:0;text-align:left;height:auto;position:relative;background:transparent;border:none;z-index:1;max-width:600px;min-width:500px;box-shadow:0 1px 0 0 rgba(0,0,0,.2),0 2px 3px 0 rgba(0,0,0,.1)}.algolia-autocomplete .ds-dropdown-menu:before{display:block;position:absolute;content:"";width:14px;height:14px;background:#fff;z-index:2;top:-7px;border-top:1px solid #d9d9d9;border-right:1px solid #d9d9d9;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);border-radius:2px}.algolia-autocomplete .ds-dropdown-menu .ds-suggestions{position:relative;z-index:2;margin-top:8px}.algolia-autocomplete .ds-dropdown-menu .ds-suggestion{cursor:pointer}.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion.suggestion-layout-simple,.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion:not(.suggestion-layout-simple) .algolia-docsearch-suggestion--content{background-color:rgba(69,142,225,.05)}.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-]{position:relative;border:1px solid #d9d9d9;background:#fff;border-radius:4px;overflow:auto;padding:0 8px 8px}.algolia-autocomplete .ds-dropdown-menu \*{box-sizing:border-box}.algolia-autocomplete .algolia-docsearch-suggestion{position:relative;padding:0 8px;background:#fff;color:#02060c;overflow:hidden}.algolia-autocomplete .algolia-docsearch-suggestion--highlight{color:#174d8c;background:rgba(143,187,237,.1);padding:.1em .05em}.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl0 .algolia-docsearch-suggestion--highlight,.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl1 .algolia-docsearch-suggestion--highlight{color:inherit;background:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight{padding:0 0 1px;background:inherit;box-shadow:inset 0 -2px 0 0 rgba(69,142,225,.8);color:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--content{display:block;float:right;width:70%;position:relative;padding:5.33333px 0 5.33333px 10.66667px;cursor:pointer}.algolia-autocomplete .algolia-docsearch-suggestion--content:before{content:"";position:absolute;display:block;top:0;height:100%;width:1px;background:#ddd;left:-1px}.algolia-autocomplete .algolia-docsearch-suggestion--category-header{position:relative;border-bottom:1px solid #ddd;display:none;margin-top:8px;padding:4px 0;font-size:1em;color:#33363d}.algolia-autocomplete .algolia-docsearch-suggestion--wrapper{width:100%;float:left;padding:8px 0 0}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column{float:left;width:30%;padding-left:0;text-align:right;position:relative;padding:5.33333px 10.66667px;color:#a4a7ae;font-size:.9em;word-wrap:break-word}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column:before{content:"";position:absolute;display:block;top:0;height:100%;width:1px;background:#ddd;right:0}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column .algolia-docsearch-suggestion--highlight{background-color:inherit;color:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-inline{display:none}.algolia-autocomplete .algolia-docsearch-suggestion--title{margin-bottom:4px;color:#02060c;font-size:.9em;font-weight:700}.algolia-autocomplete .algolia-docsearch-suggestion--text{display:block;line-height:1.2em;font-size:.85em;color:#63676d}.algolia-autocomplete .algolia-docsearch-suggestion--no-results{width:100%;padding:8px 0;text-align:center;font-size:1.2em}.algolia-autocomplete .algolia-docsearch-suggestion--no-results:before{display:none}.algolia-autocomplete .algolia-docsearch-suggestion code{padding:1px 5px;font-size:90%;border:none;color:#222;background-color:#ebebeb;border-radius:3px;font-family:Menlo,Monaco,Consolas,Courier New,monospace}.algolia-autocomplete .algolia-docsearch-suggestion code .algolia-docsearch-suggestion--highlight{background:none}.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion\_\_main .algolia-docsearch-suggestion--category-header,.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion\_\_secondary{display:block}@media (min-width:768px){.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column{display:block}}@media (max-width:768px){.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column{display:inline-block;width:auto;float:left;color:#02060c;font-size:.9em;font-weight:700;text-align:left;padding:0;opacity:.5}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column:before{display:none}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column:after{content:"|"}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content{display:inline-block;width:auto;text-align:left;float:left;padding:0}.algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content:before{display:none}}.algolia-autocomplete .suggestion-layout-simple.algolia-docsearch-suggestion{border-bottom:1px solid #eee;padding:8px;margin:0}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--content{width:100%;padding:0}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--content:before{display:none}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header{margin:0;padding:0;display:block;width:100%;border:none}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl0,.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl1{opacity:.6;font-size:.85em}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl1:before{background-image:url('data:image/svg+xml;utf8,<svg width="10" height="10" viewBox="0 0 20 38" xmlns="http://www.w3.org/2000/svg"><path d="M1.49 4.31l14 16.126.002-2.624-14 16.074-1.314 1.51 3.017 2.626 1.313-1.508 14-16.075 1.142-1.313-1.14-1.313-14-16.125L3.2.18.18 2.8l1.31 1.51z" fill-rule="evenodd" fill="%231D3657" /></svg>');content:"";width:10px;height:10px;display:inline-block}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--wrapper{width:100%;float:left;margin:0;padding:0}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--duplicate-content,.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--subcategory-inline{display:none!important}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--title{margin:0;color:#458ee1;font-size:.9em;font-weight:400}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--title:before{content:"#";font-weight:700;color:#458ee1;display:inline-block}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--text{margin:4px 0 0;display:block;line-height:1.4em;padding:5.33333px 8px;background:#f8f8f8;font-size:.85em;opacity:.8}.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight{color:#3f4145;font-weight:700;box-shadow:none}.algolia-autocomplete .algolia-docsearch-footer{width:110px;height:20px;z-index:3;margin-top:10.66667px;float:right;font-size:0;line-height:0}.algolia-autocomplete .algolia-docsearch-footer--logo{background-image:url("data:image/svg+xml;utf8,<svg viewBox='0 0 130 18' xmlns='http://www.w3.org/2000/svg'><defs><linearGradient x1='-36.868%' y1='134.936%' x2='129.432%' y2='-27.7%' id='a'><stop stop-color='%2300AEFF' offset='0%'/><stop stop-color='%233369E7' offset='100%'/></linearGradient></defs><g fill='none' fill-rule='evenodd'><path d='M59.399.022h13.299a2.372 2.372 0 0 1 2.377 2.364V15.62a2.372 2.372 0 0 1-2.377 2.364H59.399a2.372 2.372 0 0 1-2.377-2.364V2.381A2.368 2.368 0 0 1 59.399.022z' fill='url(%23a)'/><path d='M66.257 4.56c-2.815 0-5.1 2.272-5.1 5.078 0 2.806 2.284 5.072 5.1 5.072 2.815 0 5.1-2.272 5.1-5.078 0-2.806-2.279-5.072-5.1-5.072zm0 8.652c-1.983 0-3.593-1.602-3.593-3.574 0-1.972 1.61-3.574 3.593-3.574 1.983 0 3.593 1.602 3.593 3.574a3.582 3.582 0 0 1-3.593 3.574zm0-6.418v2.664c0 .076.082.131.153.093l2.377-1.226c.055-.027.071-.093.044-.147a2.96 2.96 0 0 0-2.465-1.487c-.055 0-.11.044-.11.104l.001-.001zm-3.33-1.956l-.312-.311a.783.783 0 0 0-1.106 0l-.372.37a.773.773 0 0 0 0 1.101l.307.305c.049.049.121.038.164-.011.181-.245.378-.479.597-.697.225-.223.455-.42.707-.599.055-.033.06-.109.016-.158h-.001zm5.001-.806v-.616a.781.781 0 0 0-.783-.779h-1.824a.78.78 0 0 0-.783.779v.632c0 .071.066.12.137.104a5.736 5.736 0 0 1 1.588-.223c.52 0 1.035.071 1.534.207a.106.106 0 0 0 .131-.104z' fill='%23FFF'/><path d='M102.162 13.762c0 1.455-.372 2.517-1.123 3.193-.75.676-1.895 1.013-3.44 1.013-.564 0-1.736-.109-2.673-.316l.345-1.689c.783.163 1.819.207 2.361.207.86 0 1.473-.174 1.84-.523.367-.349.548-.866.548-1.553v-.349a6.374 6.374 0 0 1-.838.316 4.151 4.151 0 0 1-1.194.158 4.515 4.515 0 0 1-1.616-.278 3.385 3.385 0 0 1-1.254-.817 3.744 3.744 0 0 1-.811-1.351c-.192-.539-.29-1.504-.29-2.212 0-.665.104-1.498.307-2.054a3.925 3.925 0 0 1 .904-1.433 4.124 4.124 0 0 1 1.441-.926 5.31 5.31 0 0 1 1.945-.365c.696 0 1.337.087 1.961.191a15.86 15.86 0 0 1 1.588.332v8.456h-.001zm-5.954-4.206c0 .893.197 1.885.592 2.299.394.414.904.621 1.528.621.34 0 .663-.049.964-.142a2.75 2.75 0 0 0 .734-.332v-5.29a8.531 8.531 0 0 0-1.413-.18c-.778-.022-1.369.294-1.786.801-.411.507-.619 1.395-.619 2.223zm16.12 0c0 .719-.104 1.264-.318 1.858a4.389 4.389 0 0 1-.904 1.52c-.389.42-.854.746-1.402.975-.548.229-1.391.36-1.813.36-.422-.005-1.26-.125-1.802-.36a4.088 4.088 0 0 1-1.397-.975 4.486 4.486 0 0 1-.909-1.52 5.037 5.037 0 0 1-.329-1.858c0-.719.099-1.411.318-1.999.219-.588.526-1.09.92-1.509.394-.42.865-.741 1.402-.97a4.547 4.547 0 0 1 1.786-.338 4.69 4.69 0 0 1 1.791.338c.548.229 1.019.55 1.402.97.389.42.69.921.909 1.509.23.588.345 1.28.345 1.999h.001zm-2.191.005c0-.921-.203-1.689-.597-2.223-.394-.539-.948-.806-1.654-.806-.707 0-1.26.267-1.654.806-.394.539-.586 1.302-.586 2.223 0 .932.197 1.558.592 2.098.394.545.948.812 1.654.812.707 0 1.26-.272 1.654-.812.394-.545.592-1.166.592-2.098h-.001zm6.962 4.707c-3.511.016-3.511-2.822-3.511-3.274L113.583.926l2.142-.338v10.003c0 .256 0 1.88 1.375 1.885v1.792h-.001zm3.774 0h-2.153V5.072l2.153-.338v9.534zm-1.079-10.542c.718 0 1.304-.578 1.304-1.291 0-.714-.581-1.291-1.304-1.291-.723 0-1.304.578-1.304 1.291 0 .714.586 1.291 1.304 1.291zm6.431 1.013c.707 0 1.304.087 1.786.262.482.174.871.42 1.156.73.285.311.488.735.608 1.182.126.447.186.937.186 1.476v5.481a25.24 25.24 0 0 1-1.495.251c-.668.098-1.419.147-2.251.147a6.829 6.829 0 0 1-1.517-.158 3.213 3.213 0 0 1-1.178-.507 2.455 2.455 0 0 1-.761-.904c-.181-.37-.274-.893-.274-1.438 0-.523.104-.855.307-1.215.208-.36.487-.654.838-.883a3.609 3.609 0 0 1 1.227-.49 7.073 7.073 0 0 1 2.202-.103c.263.027.537.076.833.147v-.349c0-.245-.027-.479-.088-.697a1.486 1.486 0 0 0-.307-.583c-.148-.169-.34-.3-.581-.392a2.536 2.536 0 0 0-.915-.163c-.493 0-.942.06-1.353.131-.411.071-.75.153-1.008.245l-.257-1.749c.268-.093.668-.185 1.183-.278a9.335 9.335 0 0 1 1.66-.142l-.001-.001zm.181 7.731c.657 0 1.145-.038 1.484-.104v-2.168a5.097 5.097 0 0 0-1.978-.104c-.241.033-.46.098-.652.191a1.167 1.167 0 0 0-.466.392c-.121.169-.175.267-.175.523 0 .501.175.79.493.981.323.196.75.289 1.293.289h.001zM84.109 4.794c.707 0 1.304.087 1.786.262.482.174.871.42 1.156.73.29.316.487.735.608 1.182.126.447.186.937.186 1.476v5.481a25.24 25.24 0 0 1-1.495.251c-.668.098-1.419.147-2.251.147a6.829 6.829 0 0 1-1.517-.158 3.213 3.213 0 0 1-1.178-.507 2.455 2.455 0 0 1-.761-.904c-.181-.37-.274-.893-.274-1.438 0-.523.104-.855.307-1.215.208-.36.487-.654.838-.883a3.609 3.609 0 0 1 1.227-.49 7.073 7.073 0 0 1 2.202-.103c.257.027.537.076.833.147v-.349c0-.245-.027-.479-.088-.697a1.486 1.486 0 0 0-.307-.583c-.148-.169-.34-.3-.581-.392a2.536 2.536 0 0 0-.915-.163c-.493 0-.942.06-1.353.131-.411.071-.75.153-1.008.245l-.257-1.749c.268-.093.668-.185 1.183-.278a8.89 8.89 0 0 1 1.66-.142l-.001-.001zm.186 7.736c.657 0 1.145-.038 1.484-.104v-2.168a5.097 5.097 0 0 0-1.978-.104c-.241.033-.46.098-.652.191a1.167 1.167 0 0 0-.466.392c-.121.169-.175.267-.175.523 0 .501.175.79.493.981.318.191.75.289 1.293.289h.001zm8.682 1.738c-3.511.016-3.511-2.822-3.511-3.274L89.461.926l2.142-.338v10.003c0 .256 0 1.88 1.375 1.885v1.792h-.001z' fill='%23182359'/><path d='M5.027 11.025c0 .698-.252 1.246-.757 1.644-.505.397-1.201.596-2.089.596-.888 0-1.615-.138-2.181-.414v-1.214c.358.168.739.301 1.141.397.403.097.778.145 1.125.145.508 0 .884-.097 1.125-.29a.945.945 0 0 0 .363-.779.978.978 0 0 0-.333-.747c-.222-.204-.68-.446-1.375-.725-.716-.29-1.221-.621-1.515-.994-.294-.372-.44-.82-.44-1.343 0-.655.233-1.171.698-1.547.466-.376 1.09-.564 1.875-.564.752 0 1.5.165 2.245.494l-.408 1.047c-.698-.294-1.321-.44-1.869-.44-.415 0-.73.09-.945.271a.89.89 0 0 0-.322.717c0 .204.043.379.129.524.086.145.227.282.424.411.197.129.551.299 1.063.51.577.24.999.464 1.268.671.269.208.466.442.591.704.125.261.188.569.188.924l-.001.002zm3.98 2.24c-.924 0-1.646-.269-2.167-.808-.521-.539-.782-1.281-.782-2.226 0-.97.242-1.733.725-2.288.483-.555 1.148-.833 1.993-.833.784 0 1.404.238 1.858.714.455.476.682 1.132.682 1.966v.682H7.357c.018.577.174 1.02.467 1.329.294.31.707.465 1.241.465.351 0 .678-.033.98-.099a5.1 5.1 0 0 0 .975-.33v1.026a3.865 3.865 0 0 1-.935.312 5.723 5.723 0 0 1-1.08.091l.002-.001zm-.231-5.199c-.401 0-.722.127-.964.381s-.386.625-.432 1.112h2.696c-.007-.491-.125-.862-.354-1.115-.229-.252-.544-.379-.945-.379l-.001.001zm7.692 5.092l-.252-.827h-.043c-.286.362-.575.608-.865.739-.29.131-.662.196-1.117.196-.584 0-1.039-.158-1.367-.473-.328-.315-.491-.761-.491-1.337 0-.612.227-1.074.682-1.386.455-.312 1.148-.482 2.079-.51l1.026-.032v-.317c0-.38-.089-.663-.266-.851-.177-.188-.452-.282-.824-.282-.304 0-.596.045-.876.134a6.68 6.68 0 0 0-.806.317l-.408-.902a4.414 4.414 0 0 1 1.058-.384 4.856 4.856 0 0 1 1.085-.132c.756 0 1.326.165 1.711.494.385.329.577.847.577 1.552v4.002h-.902l-.001-.001zm-1.88-.859c.458 0 .826-.128 1.104-.384.278-.256.416-.615.416-1.077v-.516l-.763.032c-.594.021-1.027.121-1.297.298s-.406.448-.406.814c0 .265.079.47.236.615.158.145.394.218.709.218h.001zm7.557-5.189c.254 0 .464.018.628.054l-.124 1.176a2.383 2.383 0 0 0-.559-.064c-.505 0-.914.165-1.227.494-.313.329-.47.757-.47 1.284v3.105h-1.262V7.218h.988l.167 1.047h.064c.197-.354.454-.636.771-.843a1.83 1.83 0 0 1 1.023-.312h.001zm4.125 6.155c-.899 0-1.582-.262-2.049-.787-.467-.525-.701-1.277-.701-2.259 0-.999.244-1.767.733-2.304.489-.537 1.195-.806 2.119-.806.627 0 1.191.116 1.692.349l-.381 1.015c-.534-.208-.974-.312-1.321-.312-1.028 0-1.542.682-1.542 2.046 0 .666.128 1.166.384 1.501.256.335.631.502 1.125.502a3.23 3.23 0 0 0 1.595-.419v1.101a2.53 2.53 0 0 1-.722.285 4.356 4.356 0 0 1-.932.086v.002zm8.277-.107h-1.268V9.506c0-.458-.092-.8-.277-1.026-.184-.226-.477-.338-.878-.338-.53 0-.919.158-1.168.475-.249.317-.373.848-.373 1.593v2.949h-1.262V4.801h1.262v2.122c0 .34-.021.704-.064 1.09h.081a1.76 1.76 0 0 1 .717-.666c.306-.158.663-.236 1.072-.236 1.439 0 2.159.725 2.159 2.175v3.873l-.001-.001zm7.649-6.048c.741 0 1.319.269 1.732.806.414.537.62 1.291.62 2.261 0 .974-.209 1.732-.628 2.275-.419.542-1.001.814-1.746.814-.752 0-1.336-.27-1.751-.811h-.086l-.231.704h-.945V4.801h1.262v1.987l-.021.655-.032.553h.054c.401-.591.992-.886 1.772-.886zm-.328 1.031c-.508 0-.875.149-1.098.448-.224.299-.339.799-.346 1.501v.086c0 .723.115 1.247.344 1.571.229.324.603.486 1.123.486.448 0 .787-.177 1.018-.532.231-.354.346-.867.346-1.536 0-1.35-.462-2.025-1.386-2.025l-.001.001zm3.244-.924h1.375l1.209 3.368c.183.48.304.931.365 1.354h.043c.032-.197.091-.436.177-.717.086-.281.541-1.616 1.364-4.004h1.364l-2.541 6.73c-.462 1.235-1.232 1.853-2.31 1.853-.279 0-.551-.03-.816-.091v-.999c.19.043.406.064.65.064.609 0 1.037-.353 1.284-1.058l.22-.559-2.385-5.941h.001z' fill='%231D3657'/></g></svg>");background-repeat:no-repeat;background-position:50%;background-size:100%;overflow:hidden;text-indent:-9000px;padding:0!important;width:100%;height:100%;display:block}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0;font-family:Open Sans}.container,.small-container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container:after,.container:before,.small-container:after,.small-container:before{content:" ";display:table}.container:after,.small-container:after{clear:both}.small-container{max-width:600px}.small-container h1,.small-container h2,.small-container h3,.small-container h4,.small-container h5,.small-container h6{color:#555;font-weight:400;margin:1.25em 0 .75em}.sphinxsidebar a,h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:400}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container-fluid:after,.container-fluid:before{content:" ";display:table}.container-fluid:after{clear:both}.callout{background:#000;color:#fff;display:inline-block;font-family:klavika-web,Helvetica,sans-serif;font-size:18px;font-weight:400;line-height:1;margin:0;padding:5px;letter-spacing:.05em;text-transform:uppercase}.callout.inverse{color:#000;background:#fff}.half{box-sizing:border-box;position:relative;min-height:1px}@media (min-width:992px){.half{width:50%;float:left;padding-left:15px;padding-right:15px}.container .half:first-child{padding-left:0}.container .half:last-child{padding-right:0}}h1,h2,h3,h4,h5,h6{font-family:klavika-web,Open Sans,Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:600}@font-face{font-family:klavika-web;src:url(https://graphene-python.org/static/l.11afc327.woff2) format("woff2");font-weight:700}@font-face{font-family:klavika-web;src:url(https://graphene-python.org/static/l1.ecfd3bfd.woff2) format("woff2");font-weight:600}@font-face{font-family:klavika-web;src:url(https://graphene-python.org/static/l2.ce43ec01.woff2) format("woff2");font-weight:400}@font-face{font-family:klavika-web;src:url(https://graphene-python.org/static/l3.a36a267d.woff2) format("woff2");font-weight:300}.button.primary{background:#f25f3f;border:1px solid #eb1919;color:#fff}.button{background:#fff;box-shadow:3px 4px 0 rgba(0,0,0,.1);color:#7b8a8e;display:inline-block;font-family:klavika-web,Helvetica,sans-serif;font-size:15px;font-weight:600;letter-spacing:1px;margin-bottom:4px;padding:10px 30px;text-transform:uppercase;text-decoration:none}.button,.button:hover{border:1px solid #7b8a8e}.button:hover{background:#7b8a8e;color:#fff}.button.primary:hover{background:#df4a2e;border:1px solid #eb1919}.flat-button.primary{border:1px solid #e14b2e;color:#e14b2e}.flat-button{border:1px solid #7b8a8e;color:#7b8a8e;display:inline-block;font-family:klavika-web,Helvetica,sans-serif;font-size:15px;font-weight:600;letter-spacing:1px;margin-bottom:4px;padding:10px 30px;text-transform:uppercase;text-decoration:none}.flat-button:hover{border:1px solid #333;color:#333}.flat-button.primary:hover{color:#df4a2e;border:1px solid #df4a2e}a{color:#337ab7;font-weight:700;text-decoration:none}.algolia-autocomplete .ds-dropdown-menu{border-radius:0;box-shadow:0 8px 12px 0 rgba(0,0,0,.2)}.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-]{border-radius:0}.algolia-autocomplete .algolia-docsearch-suggestion--category-header{border:none!important}.algolia-autocomplete .algolia-docsearch-suggestion--category-header>\*{background:#000;color:#fff;display:inline-block;font-family:klavika-web,Helvetica,sans-serif;font-size:16px;font-weight:400;line-height:1;margin:0;padding:4px;letter-spacing:.04em;text-transform:uppercase}.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight{box-shadow:inset 0 -2px 0 0 #e55234}.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion.suggestion-layout-simple,.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion:not(.suggestion-layout-simple) .algolia-docsearch-suggestion--content{background:rgba(230,93,29,.1)}.algolia-autocomplete .algolia-docsearch-suggestion--highlight{color:#e65d1d;background:rgba(230,93,29,.08);padding:.1em .05em}[GroupCreated with Sketch.](https://graphene-python.org/)[Documentation](https://docs.graphene-python.org/)[Team](https://graphene-python.org/team) [Github](https://github.com/graphql-python/graphene)### [Table Of Contents](index.html#document-index)

* [Getting started](index.html#document-quickstart)

* [Types Reference](index.html#document-types/index)

* [Execution](index.html#document-execution/index)

* [Relay](index.html#document-relay/index)

* [Testing in Graphene](index.html#document-testing/index)

* [API Reference](index.html#document-api/index)

[Older versions](https://readthedocs.org/projects/graphene-python/versions/) * [Docs](index.html#document-index) »

* Graphene 1.0 documentation

Graphene[¶](#graphene "Permalink to this headline")

===================================================

---

The documentation below is for the `dev` (prerelease) version of Graphene. To view the documentation for the latest stable Graphene version go to the [v2 docs](https://docs.graphene-python.org/en/stable/).

---

Contents:

Getting started[¶](#getting-started "Permalink to this headline")

-----------------------------------------------------------------

### Introduction[¶](#introduction "Permalink to this headline")

#### What is GraphQL?[¶](#what-is-graphql "Permalink to this headline")

GraphQL is a query language for your API.

It provides a standard way to:

* *describe data provided by a server* in a statically typed **Schema**

* *request data* in a **Query** which exactly describes your data requirements and

* *receive data* in a **Response** containing only the data you requested.

For an introduction to GraphQL and an overview of its concepts, please refer to [the official GraphQL documentation](http://graphql.org/learn/).

#### What is Graphene?[¶](#what-is-graphene "Permalink to this headline")

Graphene is a library that provides tools to implement a GraphQL API in Python using a *code-first* approach.

Compare Graphene’s *code-first* approach to building a GraphQL API with *schema-first* approaches like [Apollo Server](https://www.apollographql.com/docs/apollo-server/) (JavaScript) or [Ariadne](https://ariadnegraphql.org/) (Python). Instead of writing GraphQL **Schema Definition Language (SDL)**, we write Python code to describe the data provided by your server.

Graphene is fully featured with integrations for the most popular web frameworks and ORMs. Graphene produces schemas that are fully compliant with the GraphQL spec and provides tools and patterns for building a Relay-Compliant API as well.

### An example in Graphene[¶](#an-example-in-graphene "Permalink to this headline")

Let’s build a basic GraphQL schema to say “hello” and “goodbye” in Graphene.

When we send a **Query** requesting only one **Field**, `hello`, and specify a value for the `firstName` **Argument**...

```

{

  hello(firstName: "friend")

}

```

...we would expect the following Response containing only the data requested (the `goodbye` field is not resolved).

```

{

  "data": {

    "hello": "Hello friend!"

  }

}

```

#### Requirements[¶](#requirements "Permalink to this headline")

* Python (3.6, 3.7, 3.8, 3.9, 3.10, pypy)

* Graphene (3.0)

#### Project setup[¶](#project-setup "Permalink to this headline")

```

pip install "graphene>=3.0"

```

#### Creating a basic Schema[¶](#creating-a-basic-schema "Permalink to this headline")

In Graphene, we can define a simple schema using the following code:

```

from graphene import ObjectType, String, Schema

class Query(ObjectType):

    # this defines a Field `hello` in our Schema with a single Argument `first\_name`

    # By default, the argument name will automatically be camel-based into firstName in the generated schema

    hello = String(first\_name=String(default\_value="stranger"))

    goodbye = String()

    # our Resolver method takes the GraphQL context (root, info) as well as

    # Argument (first\_name) for the Field and returns data for the query Response

    def resolve\_hello(root, info, first\_name):

        return f'Hello {first\_name}!'

    def resolve\_goodbye(root, info):

        return 'See ya!'

schema = Schema(query=Query)

```

A GraphQL **Schema** describes each **Field** in the data model provided by the server using scalar types like *String*, *Int* and *Enum* and compound types like *List* and *Object*. For more details refer to the Graphene [Types Reference](index.html#typesreference).

Our schema can also define any number of **Arguments** for our **Fields**. This is a powerful way for a **Query** to describe the exact data requirements for each **Field**.

For each **Field** in our **Schema**, we write a **Resolver** method to fetch data requested by a client’s **Query** using the current context and **Arguments**. For more details, refer to this section on [Resolvers](index.html#resolvers).

#### Schema Definition Language (SDL)[¶](#schema-definition-language-sdl "Permalink to this headline")

In the [GraphQL Schema Definition Language](https://graphql.org/learn/schema/), we could describe the fields defined by our example code as shown below.

```

type Query {

  hello(firstName: String = "stranger"): String

  goodbye: String

}

```

Further examples in this documentation will use SDL to describe schema created by ObjectTypes and other fields.

#### Querying[¶](#querying "Permalink to this headline")

Then we can start querying our **Schema** by passing a GraphQL query string to `execute`:

```

# we can query for our field (with the default argument)

query\_string = '{ hello }'

result = schema.execute(query\_string)

print(result.data['hello'])

# "Hello stranger!"

# or passing the argument in the query

query\_with\_argument = '{ hello(firstName: "GraphQL") }'

result = schema.execute(query\_with\_argument)

print(result.data['hello'])

# "Hello GraphQL!"

```

#### Next steps[¶](#next-steps "Permalink to this headline")

Congrats! You got your first Graphene schema working!

Normally, we don’t need to directly execute a query string against our schema as Graphene provides many useful Integrations with popular web frameworks like Flask and Django. Check out [Integrations](index.html#integrations) for more information on how to get started serving your GraphQL API.

Types Reference[¶](#types-reference "Permalink to this headline")

-----------------------------------------------------------------

### Schema[¶](#schema "Permalink to this headline")

A GraphQL **Schema** defines the types and relationships between **Fields** in your API.

A Schema is created by supplying the root [ObjectType](index.html#objecttype) of each operation, query (mandatory), mutation and subscription.

Schema will collect all type definitions related to the root operations and then supply them to the validator and executor.

```

my\_schema = Schema(

    query=MyRootQuery,

    mutation=MyRootMutation,

    subscription=MyRootSubscription

)

```

A Root Query is just a special [ObjectType](index.html#objecttype) that defines the fields that are the entrypoint for your API. Root Mutation and Root Subscription are similar to Root Query, but for different operation types:

* Query fetches data

* Mutation changes data and retrieves the changes

* Subscription sends changes to clients in real-time

Review the [GraphQL documentation on Schema](https://graphql.org/learn/schema/) for a brief overview of fields, schema and operations.

#### Querying[¶](#querying "Permalink to this headline")

To query a schema, call the `execute` method on it. See [Executing a query](index.html#schemaexecute) for more details.

```

query\_string = 'query whoIsMyBestFriend { myBestFriend { lastName } }'

my\_schema.execute(query\_string)

```

#### Types[¶](#types "Permalink to this headline")

There are some cases where the schema cannot access all of the types that we plan to have.

For example, when a field returns an `Interface`, the schema doesn’t know about any of the

implementations.

In this case, we need to use the `types` argument when creating the Schema:

```

my\_schema = Schema(

    query=MyRootQuery,

    types=[SomeExtraObjectType, ]

)

```

#### Auto camelCase field names[¶](#auto-camelcase-field-names "Permalink to this headline")

By default all field and argument names (that are not

explicitly set with the `name` arg) will be converted from

`snake\_case` to `camelCase` (as the API is usually being consumed by a js/mobile client)

For example with the ObjectType the `last\_name` field name is converted to `lastName`:

```

class Person(graphene.ObjectType):

    last\_name = graphene.String()

    other\_name = graphene.String(name='\_other\_Name')

```

In case you don’t want to apply this transformation, provide a `name` argument to the field constructor.

`other\_name` converts to `\_other\_Name` (without further transformations).

Your query should look like:

```

{

    lastName

    \_other\_Name

}

```

To disable this behavior, set the `auto\_camelcase` to `False` upon schema instantiation:

```

my\_schema = Schema(

    query=MyRootQuery,

    auto\_camelcase=False,

)

```

### Scalars[¶](#scalars "Permalink to this headline")

Scalar types represent concrete values at the leaves of a query. There are

several built in types that Graphene provides out of the box which represent common

values in Python. You can also create your own Scalar types to better express

values that you might have in your data model.

All Scalar types accept the following arguments. All are optional:

`name`: *string*

> 

> Override the name of the Field.

`description`: *string*

> 

> A description of the type to show in the GraphiQL browser.

`required`: *boolean*

> 

> If `True`, the server will enforce a value for this field. See [NonNull](../list-and-nonnull.html#nonnull). Default is `False`.

`deprecation\_reason`: *string*

> 

> Provide a deprecation reason for the Field.

`default\_value`: *any*

> 

> Provide a default value for the Field.

#### Built in scalars[¶](#built-in-scalars "Permalink to this headline")

Graphene defines the following base Scalar Types that match the default [GraphQL types](https://graphql.org/learn/schema/#scalar-types):

##### `graphene.String`[¶](#graphene-string "Permalink to this headline")

> 

> Represents textual data, represented as UTF-8

> character sequences. The String type is most often used by GraphQL to

> represent free-form human-readable text.

##### `graphene.Int`[¶](#graphene-int "Permalink to this headline")

> 

> Represents non-fractional signed whole numeric

> values. Int is a signed 32‐bit integer per the

> [GraphQL spec](https://facebook.github.io/graphql/June2018/#sec-Int)

##### `graphene.Float`[¶](#graphene-float "Permalink to this headline")

> 

> Represents signed double-precision fractional

> values as specified by

> [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).

##### `graphene.Boolean`[¶](#graphene-boolean "Permalink to this headline")

> 

> Represents true or false.

##### `graphene.ID`[¶](#graphene-id "Permalink to this headline")

> 

> Represents a unique identifier, often used to

> refetch an object or as key for a cache. The ID type appears in a JSON

> response as a String; however, it is not intended to be human-readable.

> When expected as an input type, any string (such as “4”) or integer

> (such as 4) input value will be accepted as an ID.

---

Graphene also provides custom scalars for common values:

##### `graphene.Date`[¶](#graphene-date "Permalink to this headline")

> 

> Represents a Date value as specified by [iso8601](https://en.wikipedia.org/wiki/ISO_8601).

```

import datetime

from graphene import Schema, ObjectType, Date

class Query(ObjectType):

    one\_week\_from = Date(required=True, date\_input=Date(required=True))

    def resolve\_one\_week\_from(root, info, date\_input):

        assert date\_input == datetime.date(2006, 1, 2)

        return date\_input + datetime.timedelta(weeks=1)

schema = Schema(query=Query)

results = schema.execute("""

 query {

 oneWeekFrom(dateInput: "2006-01-02")

 }

""")

assert results.data == {"oneWeekFrom": "2006-01-09"}

```

##### `graphene.DateTime`[¶](#graphene-datetime "Permalink to this headline")

> 

> Represents a DateTime value as specified by [iso8601](https://en.wikipedia.org/wiki/ISO_8601).

```

import datetime

from graphene import Schema, ObjectType, DateTime

class Query(ObjectType):

    one\_hour\_from = DateTime(required=True, datetime\_input=DateTime(required=True))

    def resolve\_one\_hour\_from(root, info, datetime\_input):

        assert datetime\_input == datetime.datetime(2006, 1, 2, 15, 4, 5)

        return datetime\_input + datetime.timedelta(hours=1)

schema = Schema(query=Query)

results = schema.execute("""

 query {

 oneHourFrom(datetimeInput: "2006-01-02T15:04:05")

 }

""")

assert results.data == {"oneHourFrom": "2006-01-02T16:04:05"}

```

##### `graphene.Time`[¶](#graphene-time "Permalink to this headline")

> 

> Represents a Time value as specified by [iso8601](https://en.wikipedia.org/wiki/ISO_8601).

```

import datetime

from graphene import Schema, ObjectType, Time

class Query(ObjectType):

    one\_hour\_from = Time(required=True, time\_input=Time(required=True))

    def resolve\_one\_hour\_from(root, info, time\_input):

        assert time\_input == datetime.time(15, 4, 5)

        tmp\_time\_input = datetime.datetime.combine(datetime.date(1, 1, 1), time\_input)

        return (tmp\_time\_input + datetime.timedelta(hours=1)).time()

schema = Schema(query=Query)

results = schema.execute("""

 query {

 oneHourFrom(timeInput: "15:04:05")

 }

""")

assert results.data == {"oneHourFrom": "16:04:05"}

```

##### `graphene.Decimal`[¶](#graphene-decimal "Permalink to this headline")

> 

> Represents a Python Decimal value.

```

import decimal

from graphene import Schema, ObjectType, Decimal

class Query(ObjectType):

    add\_one\_to = Decimal(required=True, decimal\_input=Decimal(required=True))

    def resolve\_add\_one\_to(root, info, decimal\_input):

        assert decimal\_input == decimal.Decimal("10.50")

        return decimal\_input + decimal.Decimal("1")

schema = Schema(query=Query)

results = schema.execute("""

 query {

 addOneTo(decimalInput: "10.50")

 }

""")

assert results.data == {"addOneTo": "11.50"}

```

##### `graphene.JSONString`[¶](#graphene-jsonstring "Permalink to this headline")

> 

> Represents a JSON string.

```

from graphene import Schema, ObjectType, JSONString, String

class Query(ObjectType):

    update\_json\_key = JSONString(

        required=True,

        json\_input=JSONString(required=True),

        key=String(required=True),

        value=String(required=True)

    )

    def resolve\_update\_json\_key(root, info, json\_input, key, value):

        assert json\_input == {"name": "Jane"}

        json\_input[key] = value

        return json\_input

schema = Schema(query=Query)

results = schema.execute("""

 query {

 updateJsonKey(jsonInput: "{\\"name\\": \\"Jane\\"}", key: "name", value: "Beth")

 }

""")

assert results.data == {"updateJsonKey": "{\"name\": \"Beth\"}"}

```

##### `graphene.Base64`[¶](#graphene-base64 "Permalink to this headline")

> 

> Represents a Base64 encoded string.

```

from graphene import Schema, ObjectType, Base64

class Query(ObjectType):

    increment\_encoded\_id = Base64(

        required=True,

        base64\_input=Base64(required=True),

    )

    def resolve\_increment\_encoded\_id(root, info, base64\_input):

        assert base64\_input == "4"

        return int(base64\_input) + 1

schema = Schema(query=Query)

results = schema.execute("""

 query {

 incrementEncodedId(base64Input: "NA==")

 }

""")

assert results.data == {"incrementEncodedId": "NQ=="}

```

#### Custom scalars[¶](#custom-scalars "Permalink to this headline")

You can create custom scalars for your schema.

The following is an example for creating a DateTime scalar:

```

import datetime

from graphene.types import Scalar

from graphql.language import ast

class DateTime(Scalar):

    '''DateTime Scalar Description'''

    @staticmethod

    def serialize(dt):

        return dt.isoformat()

    @staticmethod

    def parse\_literal(node, \_variables=None):

        if isinstance(node, ast.StringValue):

            return datetime.datetime.strptime(

                node.value, "%Y-%m-%dT%H:%M:%S.%f")

    @staticmethod

    def parse\_value(value):

        return datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")

```

#### Mounting Scalars[¶](#mounting-scalars "Permalink to this headline")

Scalars mounted in a `ObjectType`, `Interface` or `Mutation` act as

`Field`s.

```

class Person(graphene.ObjectType):

    name = graphene.String()

# Is equivalent to:

class Person(graphene.ObjectType):

    name = graphene.Field(graphene.String)

```

**Note:** when using the `Field` constructor directly, pass the type and

not an instance.

Types mounted in a `Field` act as `Argument`s.

```

graphene.Field(graphene.String, to=graphene.String())

# Is equivalent to:

graphene.Field(graphene.String, to=graphene.Argument(graphene.String))

```

### Lists and Non-Null[¶](#lists-and-non-null "Permalink to this headline")

Object types, scalars, and enums are the only kinds of types you can

define in Graphene. But when you use the types in other parts of the

schema, or in your query variable declarations, you can apply additional

type modifiers that affect validation of those values.

#### NonNull[¶](#nonnull "Permalink to this headline")

```

import graphene

class Character(graphene.ObjectType):

    name = graphene.NonNull(graphene.String)

```

Here, we’re using a `String` type and marking it as Non-Null by wrapping

it using the `NonNull` class. This means that our server always expects

to return a non-null value for this field, and if it ends up getting a

null value that will actually trigger a GraphQL execution error,

letting the client know that something has gone wrong.

The previous `NonNull` code snippet is also equivalent to:

```

import graphene

class Character(graphene.ObjectType):

    name = graphene.String(required=True)

```

#### List[¶](#list "Permalink to this headline")

```

import graphene

class Character(graphene.ObjectType):

    appears\_in = graphene.List(graphene.String)

```

Lists work in a similar way: We can use a type modifier to mark a type as a

`List`, which indicates that this field will return a list of that type.

It works the same for arguments, where the validation step will expect a list

for that value.

#### NonNull Lists[¶](#nonnull-lists "Permalink to this headline")

By default items in a list will be considered nullable. To define a list without

any nullable items the type needs to be marked as `NonNull`. For example:

```

import graphene

class Character(graphene.ObjectType):

    appears\_in = graphene.List(graphene.NonNull(graphene.String))

```

The above results in the type definition:

```

type Character {

    appearsIn: [String!]

}

```

### ObjectType[¶](#objecttype "Permalink to this headline")

A Graphene *ObjectType* is the building block used to define the relationship between **Fields** in your **Schema** and how their data is retrieved.

The basics:

* Each ObjectType is a Python class that inherits from `graphene.ObjectType`.

* Each attribute of the ObjectType represents a `Field`.

* Each `Field` has a [resolver method](#resolvers) to fetch data (or [Default Resolver](#defaultresolver)).

#### Quick example[¶](#quick-example "Permalink to this headline")

This example model defines a Person, with a first and a last name:

```

from graphene import ObjectType, String

class Person(ObjectType):

    first\_name = String()

    last\_name = String()

    full\_name = String()

    def resolve\_full\_name(parent, info):

        return f"{parent.first\_name} {parent.last\_name}"

```

This *ObjectType* defines the field **first\_name**, **last\_name**, and **full\_name**. Each field is specified as a class attribute, and each attribute maps to a Field. Data is fetched by our `resolve\_full\_name` [resolver method](#resolvers) for `full\_name` field and the [Default Resolver](#defaultresolver) for other fields.

The above `Person` ObjectType has the following schema representation:

```

type Person {

  firstName: String

  lastName: String

  fullName: String

}

```

#### Resolvers[¶](#resolvers "Permalink to this headline")

A **Resolver** is a method that helps us answer **Queries** by fetching data for a **Field** in our **Schema**.

Resolvers are lazily executed, so if a field is not included in a query, its resolver will not be executed.

Each field on an *ObjectType* in Graphene should have a corresponding resolver method to fetch data. This resolver method should match the field name. For example, in the `Person` type above, the `full\_name` field is resolved by the method `resolve\_full\_name`.

Each resolver method takes the parameters:

* [Parent Value Object (parent)](#resolverparamparent) for the value object use to resolve most fields

* [GraphQL Execution Info (info)](#resolverparaminfo) for query and schema meta information and per-request context

* [GraphQL Arguments (\*\*kwargs)](#resolverparamgraphqlarguments) as defined on the **Field**.

##### Resolver Parameters[¶](#resolver-parameters "Permalink to this headline")

###### Parent Value Object (*parent*)[¶](#parent-value-object-parent "Permalink to this headline")

This parameter is typically used to derive the values for most fields on an *ObjectType*.

The first parameter of a resolver method (*parent*) is the value object returned from the resolver of the parent field. If there is no parent field, such as a root Query field, then the value for *parent* is set to the `root\_value` configured while executing the query (default `None`). See [Executing a query](index.html#schemaexecute) for more details on executing queries.

####### Resolver example[¶](#resolver-example "Permalink to this headline")

If we have a schema with Person type and one field on the root query.

```

from graphene import ObjectType, String, Field

class Person(ObjectType):

    full\_name = String()

    def resolve\_full\_name(parent, info):

        return f"{parent.first\_name} {parent.last\_name}"

class Query(ObjectType):

    me = Field(Person)

    def resolve\_me(parent, info):

        # returns an object that represents a Person

        return get\_human(name="Luke Skywalker")

```

When we execute a query against that schema.

```

schema = Schema(query=Query)

query\_string = "{ me { fullName } }"

result = schema.execute(query\_string)

assert result.data["me"] == {"fullName": "Luke Skywalker"}

```

Then we go through the following steps to resolve this query:

* `parent` is set with the root\_value from query execution (None).

* `Query.resolve\_me` called with `parent` None which returns a value object `Person("Luke", "Skywalker")`.

* This value object is then used as `parent` while calling `Person.resolve\_full\_name` to resolve the scalar String value “Luke Skywalker”.

* The scalar value is serialized and sent back in the query response.

Each resolver returns the next [Parent Value Object (parent)](#resolverparamparent) to be used in executing the following resolver in the chain. If the Field is a Scalar type, that value will be serialized and sent in the **Response**. Otherwise, while resolving Compound types like *ObjectType*, the value be passed forward as the next [Parent Value Object (parent)](#resolverparamparent).

####### Naming convention[¶](#naming-convention "Permalink to this headline")

This [Parent Value Object (parent)](#resolverparamparent) is sometimes named `obj`, `parent`, or `source` in other GraphQL documentation. It can also be named after the value object being resolved (ex. `root` for a root Query or Mutation, and `person` for a Person value object). Sometimes this argument will be named `self` in Graphene code, but this can be misleading due to [Implicit staticmethod](#resolverimplicitstaticmethod) while executing queries in Graphene.

###### GraphQL Execution Info (*info*)[¶](#graphql-execution-info-info "Permalink to this headline")

The second parameter provides two things:

* reference to meta information about the execution of the current GraphQL Query (fields, schema, parsed query, etc.)

* access to per-request `context` which can be used to store user authentication, data loader instances or anything else useful for resolving the query.

Only context will be required for most applications. See [Context](index.html#schemaexecutecontext) for more information about setting context.

###### GraphQL Arguments (*\*\*kwargs*)[¶](#graphql-arguments-kwargs "Permalink to this headline")

Any arguments that a field defines gets passed to the resolver function as

keyword arguments. For example:

```

from graphene import ObjectType, Field, String

class Query(ObjectType):

    human\_by\_name = Field(Human, name=String(required=True))

    def resolve\_human\_by\_name(parent, info, name):

        return get\_human(name=name)

```

You can then execute the following query:

```

query {

    humanByName(name: "Luke Skywalker") {

        firstName

        lastName

    }

}

```

*Note:* There are several arguments to a field that are “reserved” by Graphene

(see [Fields (Mounted Types)](index.html#fields-mounted-types)).

You can still define an argument that clashes with one of these fields by using

the `args` parameter like so:

```

from graphene import ObjectType, Field, String

class Query(ObjectType):

    answer = String(args={'description': String()})

    def resolve\_answer(parent, info, description):

        return description

```

##### Convenience Features of Graphene Resolvers[¶](#convenience-features-of-graphene-resolvers "Permalink to this headline")

###### Implicit staticmethod[¶](#implicit-staticmethod "Permalink to this headline")

One surprising feature of Graphene is that all resolver methods are treated implicitly as staticmethods. This means that, unlike other methods in Python, the first argument of a resolver is *never* `self` while it is being executed by Graphene. Instead, the first argument is always [Parent Value Object (parent)](#resolverparamparent). In practice, this is very convenient as, in GraphQL, we are almost always more concerned with the using the parent value object to resolve queries than attributes on the Python object itself.

The two resolvers in this example are effectively the same.

```

from graphene import ObjectType, String

class Person(ObjectType):

    first\_name = String()

    last\_name = String()

    @staticmethod

    def resolve\_first\_name(parent, info):

        '''

 Decorating a Python method with `staticmethod` ensures that `self` will not be provided as an

 argument. However, Graphene does not need this decorator for this behavior.

 '''

        return parent.first\_name

    def resolve\_last\_name(parent, info):

        '''

 Normally the first argument for this method would be `self`, but Graphene executes this as

 a staticmethod implicitly.

 '''

        return parent.last\_name

    # ...

```

If you prefer your code to be more explicit, feel free to use `@staticmethod` decorators. Otherwise, your code may be cleaner without them!

###### Default Resolver[¶](#default-resolver "Permalink to this headline")

If a resolver method is not defined for a **Field** attribute on our *ObjectType*, Graphene supplies a default resolver.

If the [Parent Value Object (parent)](#resolverparamparent) is a dictionary, the resolver will look for a dictionary key matching the field name. Otherwise, the resolver will get the attribute from the parent value object matching the field name.

```

from collections import namedtuple

from graphene import ObjectType, String, Field, Schema

PersonValueObject = namedtuple("Person", ["first\_name", "last\_name"])

class Person(ObjectType):

    first\_name = String()

    last\_name = String()

class Query(ObjectType):

    me = Field(Person)

    my\_best\_friend = Field(Person)

    def resolve\_me(parent, info):

        # always pass an object for `me` field

        return PersonValueObject(first\_name="Luke", last\_name="Skywalker")

    def resolve\_my\_best\_friend(parent, info):

        # always pass a dictionary for `my\_best\_fiend\_field`

        return {"first\_name": "R2", "last\_name": "D2"}

schema = Schema(query=Query)

result = schema.execute('''

 {

 me { firstName lastName }

 myBestFriend { firstName lastName }

 }

''')

# With default resolvers we can resolve attributes from an object..

assert result.data["me"] == {"firstName": "Luke", "lastName": "Skywalker"}

# With default resolvers, we can also resolve keys from a dictionary..

assert result.data["myBestFriend"] == {"firstName": "R2", "lastName": "D2"}

```

##### Advanced[¶](#advanced "Permalink to this headline")

###### GraphQL Argument defaults[¶](#graphql-argument-defaults "Permalink to this headline")

If you define an argument for a field that is not required (and in a query

execution it is not provided as an argument) it will not be passed to the

resolver function at all. This is so that the developer can differentiate

between a `undefined` value for an argument and an explicit `null` value.

For example, given this schema:

```

from graphene import ObjectType, String

class Query(ObjectType):

    hello = String(required=True, name=String())

    def resolve\_hello(parent, info, name):

        return name if name else 'World'

```

And this query:

```

query {

    hello

}

```

An error will be thrown:

```

TypeError: resolve\_hello() missing 1 required positional argument: 'name'

```

You can fix this error in several ways. Either by combining all keyword arguments

into a dict:

```

from graphene import ObjectType, String

class Query(ObjectType):

    hello = String(required=True, name=String())

    def resolve\_hello(parent, info, \*\*kwargs):

        name = kwargs.get('name', 'World')

        return f'Hello, {name}!'

```

Or by setting a default value for the keyword argument:

```

from graphene import ObjectType, String

class Query(ObjectType):

    hello = String(required=True, name=String())

    def resolve\_hello(parent, info, name='World'):

        return f'Hello, {name}!'

```

One can also set a default value for an Argument in the GraphQL schema itself using Graphene!

```

from graphene import ObjectType, String

class Query(ObjectType):

    hello = String(

        required=True,

        name=String(default\_value='World')

    )

    def resolve\_hello(parent, info, name):

        return f'Hello, {name}!'

```

###### Resolvers outside the class[¶](#resolvers-outside-the-class "Permalink to this headline")

A field can use a custom resolver from outside the class:

```

from graphene import ObjectType, String

def resolve\_full\_name(person, info):

    return f"{person.first\_name} {person.last\_name}"

class Person(ObjectType):

    first\_name = String()

    last\_name = String()

    full\_name = String(resolver=resolve\_full\_name)

```

###### Instances as value objects[¶](#instances-as-value-objects "Permalink to this headline")

Graphene `ObjectType`s can act as value objects too. So with the

previous example you could use `Person` to capture data for each of the *ObjectType*‘s fields.

```

peter = Person(first\_name='Peter', last\_name='Griffin')

peter.first\_name  # prints "Peter"

peter.last\_name  # prints "Griffin"

```

###### Field camelcasing[¶](#field-camelcasing "Permalink to this headline")

Graphene automatically camelcases fields on *ObjectType* from `field\_name` to `fieldName` to conform with GraphQL standards. See [Auto camelCase field names](index.html#schemaautocamelcase) for more information.

#### *ObjectType* Configuration - Meta class[¶](#objecttype-configuration-meta-class "Permalink to this headline")

Graphene uses a Meta inner class on *ObjectType* to set different options.

##### GraphQL type name[¶](#graphql-type-name "Permalink to this headline")

By default the type name in the GraphQL schema will be the same as the class name

that defines the `ObjectType`. This can be changed by setting the `name`

property on the `Meta` class:

```

from graphene import ObjectType

class MyGraphQlSong(ObjectType):

    class Meta:

        name = 'Song'

```

##### GraphQL Description[¶](#graphql-description "Permalink to this headline")

The schema description of an *ObjectType* can be set as a docstring on the Python object or on the Meta inner class.

```

from graphene import ObjectType

class MyGraphQlSong(ObjectType):

    ''' We can set the schema description for an Object Type here on a docstring '''

    class Meta:

        description = 'But if we set the description in Meta, this value is used instead'

```

##### Interfaces & Possible Types[¶](#interfaces-possible-types "Permalink to this headline")

Setting `interfaces` in Meta inner class specifies the GraphQL Interfaces that this Object implements.

Providing `possible\_types` helps Graphene resolve ambiguous types such as interfaces or Unions.

See [Interfaces](index.html#interfaces) for more information.

```

from graphene import ObjectType, Node

Song = namedtuple('Song', ('title', 'artist'))

class MyGraphQlSong(ObjectType):

    class Meta:

        interfaces = (Node, )

        possible\_types = (Song, )

```

### Enums[¶](#enums "Permalink to this headline")

An `Enum` is a special `GraphQL` type that represents a set of

symbolic names (members) bound to unique, constant values.

#### Definition[¶](#definition "Permalink to this headline")

You can create an `Enum` using classes:

```

import graphene

class Episode(graphene.Enum):

    NEWHOPE = 4

    EMPIRE = 5

    JEDI = 6

```

But also using instances of Enum:

```

Episode = graphene.Enum('Episode', [('NEWHOPE', 4), ('EMPIRE', 5), ('JEDI', 6)])

```

#### Value descriptions[¶](#value-descriptions "Permalink to this headline")

It’s possible to add a description to an enum value, for that the enum value

needs to have the `description` property on it.

```

class Episode(graphene.Enum):

    NEWHOPE = 4

    EMPIRE = 5

    JEDI = 6

    @property

    def description(self):

        if self == Episode.NEWHOPE:

            return 'New Hope Episode'

        return 'Other episode'

```

#### Usage with Python Enums[¶](#usage-with-python-enums "Permalink to this headline")

In case the Enums are already defined it’s possible to reuse them using

the `Enum.from\_enum` function.

```

graphene.Enum.from\_enum(AlreadyExistingPyEnum)

```

`Enum.from\_enum` supports a `description` and `deprecation\_reason` lambdas as input so

you can add description etc. to your enum without changing the original:

```

graphene.Enum.from\_enum(

    AlreadyExistingPyEnum,

    description=lambda v: return 'foo' if v == AlreadyExistingPyEnum.Foo else 'bar'

)

```

#### Notes[¶](#notes "Permalink to this headline")

`graphene.Enum` uses [`enum.Enum`](https://docs.python.org/3/library/enum.html) internally (or a backport if

that’s not available) and can be used in a similar way, with the exception of

member getters.

In the Python `Enum` implementation you can access a member by initing the Enum.

```

from enum import Enum

class Color(Enum):

    RED = 1

    GREEN = 2

    BLUE = 3

assert Color(1) == Color.RED

```

However, in Graphene `Enum` you need to call .get to have the same effect:

```

from graphene import Enum

class Color(Enum):

    RED = 1

    GREEN = 2

    BLUE = 3

assert Color.get(1) == Color.RED

```

### Interfaces[¶](#interfaces "Permalink to this headline")

An *Interface* is an abstract type that defines a certain set of fields that a

type must include to implement the interface.

For example, you can define an Interface `Character` that represents any

character in the Star Wars trilogy:

```

import graphene

class Character(graphene.Interface):

    id = graphene.ID(required=True)

    name = graphene.String(required=True)

    friends = graphene.List(lambda: Character)

```

Any ObjectType that implements `Character` will have these exact fields, with

these arguments and return types.

For example, here are some types that might implement `Character`:

```

class Human(graphene.ObjectType):

    class Meta:

        interfaces = (Character, )

    starships = graphene.List(Starship)

    home\_planet = graphene.String()

class Droid(graphene.ObjectType):

    class Meta:

        interfaces = (Character, )

    primary\_function = graphene.String()

```

Both of these types have all of the fields from the `Character` interface,

but also bring in extra fields, `home\_planet`, `starships` and

`primary\_function`, that are specific to that particular type of character.

The full GraphQL schema definition will look like this:

```

interface Character {

    id: ID!

    name: String!

    friends: [Character]

}

type Human implements Character {

    id: ID!

    name: String!

    friends: [Character]

    starships: [Starship]

    homePlanet: String

}

type Droid implements Character {

    id: ID!

    name: String!

    friends: [Character]

    primaryFunction: String

}

```

Interfaces are useful when you want to return an object or set of objects,

which might be of several different types.

For example, you can define a field `hero` that resolves to any

`Character`, depending on the episode, like this:

```

class Query(graphene.ObjectType):

    hero = graphene.Field(

        Character,

        required=True,

        episode=graphene.Int(required=True)

    )

    def resolve\_hero(root, info, episode):

        # Luke is the hero of Episode V

        if episode == 5:

            return get\_human(name='Luke Skywalker')

        return get\_droid(name='R2-D2')

schema = graphene.Schema(query=Query, types=[Human, Droid])

```

This allows you to directly query for fields that exist on the Character interface

as well as selecting specific fields on any type that implements the interface

using [inline fragments](https://graphql.org/learn/queries/#inline-fragments).

For example, the following query:

```

query HeroForEpisode($episode: Int!) {

    hero(episode: $episode) {

        __typename

        name

        ... on Droid {

            primaryFunction

        }

        ... on Human {

            homePlanet

        }

    }

}

```

Will return the following data with variables `{ "episode": 4 }`:

```

{

    "data": {

        "hero": {

            "\_\_typename": "Droid",

            "name": "R2-D2",

            "primaryFunction": "Astromech"

        }

    }

}

```

And different data with the variables `{ "episode": 5 }`:

```

{

    "data": {

        "hero": {

            "\_\_typename": "Human",

            "name": "Luke Skywalker",

            "homePlanet": "Tatooine"

        }

    }

}

```

#### Resolving data objects to types[¶](#resolving-data-objects-to-types "Permalink to this headline")

As you build out your schema in Graphene it’s common for your resolvers to

return objects that represent the data backing your GraphQL types rather than

instances of the Graphene types (e.g. Django or SQLAlchemy models). This works

well with `ObjectType` and `Scalar` fields, however when you start using

Interfaces you might come across this error:

```

"Abstract type Character must resolve to an Object type at runtime for field Query.hero ..."

```

This happens because Graphene doesn’t have enough information to convert the

data object into a Graphene type needed to resolve the `Interface`. To solve

this you can define a `resolve\_type` class method on the `Interface` which

maps a data object to a Graphene type:

```

class Character(graphene.Interface):

    id = graphene.ID(required=True)

    name = graphene.String(required=True)

    @classmethod

    def resolve\_type(cls, instance, info):

        if instance.type == 'DROID':

            return Droid

        return Human

```

### Unions[¶](#unions "Permalink to this headline")

Union types are very similar to interfaces, but they don’t get

to specify any common fields between the types.

The basics:

* Each Union is a Python class that inherits from `graphene.Union`.

* Unions don’t have any fields on it, just links to the possible ObjectTypes.

#### Quick example[¶](#quick-example "Permalink to this headline")

This example model defines several ObjectTypes with their own fields.

`SearchResult` is the implementation of `Union` of this object types.

```

import graphene

class Human(graphene.ObjectType):

    name = graphene.String()

    born\_in = graphene.String()

class Droid(graphene.ObjectType):

    name = graphene.String()

    primary\_function = graphene.String()

class Starship(graphene.ObjectType):

    name = graphene.String()

    length = graphene.Int()

class SearchResult(graphene.Union):

    class Meta:

        types = (Human, Droid, Starship)

```

Wherever we return a SearchResult type in our schema, we might get a Human, a Droid, or a Starship.

Note that members of a union type need to be concrete object types;

you can’t create a union type out of interfaces or other unions.

The above types have the following representation in a schema:

```

type Droid {

  name: String

  primaryFunction: String

}

type Human {

  name: String

  bornIn: String

}

type Ship {

  name: String

  length: Int

}

union SearchResult = Human | Droid | Starship

```

### Mutations[¶](#mutations "Permalink to this headline")

A Mutation is a special ObjectType that also defines an Input.

#### Quick example[¶](#quick-example "Permalink to this headline")

This example defines a Mutation:

```

import graphene

class CreatePerson(graphene.Mutation):

    class Arguments:

        name = graphene.String()

    ok = graphene.Boolean()

    person = graphene.Field(lambda: Person)

    def mutate(root, info, name):

        person = Person(name=name)

        ok = True

        return CreatePerson(person=person, ok=ok)

```

**person** and **ok** are the output fields of the Mutation when it is

resolved.

**Arguments** attributes are the arguments that the Mutation

`CreatePerson` needs for resolving, in this case **name** will be the

only argument for the mutation.

**mutate** is the function that will be applied once the mutation is

called. This method is just a special resolver that we can change

data within. It takes the same arguments as the standard query [Resolver Parameters](index.html#resolverarguments).

So, we can finish our schema like this:

```

# ... the Mutation Class

class Person(graphene.ObjectType):

    name = graphene.String()

    age = graphene.Int()

class MyMutations(graphene.ObjectType):

    create\_person = CreatePerson.Field()

# We must define a query for our schema

class Query(graphene.ObjectType):

    person = graphene.Field(Person)

schema = graphene.Schema(query=Query, mutation=MyMutations)

```

#### Executing the Mutation[¶](#executing-the-mutation "Permalink to this headline")

Then, if we query (`schema.execute(query\_str)`) the following:

```

mutation myFirstMutation {

    createPerson(name:"Peter") {

        person {

            name

        }

        ok

    }

}

```

We should receive:

```

{

    "createPerson": {

        "person" : {

            "name": "Peter"

        },

        "ok": true

    }

}

```

#### InputFields and InputObjectTypes[¶](#inputfields-and-inputobjecttypes "Permalink to this headline")

InputFields are used in mutations to allow nested input data for mutations.

To use an InputField you define an InputObjectType that specifies the structure of your input data:

```

import graphene

class PersonInput(graphene.InputObjectType):

    name = graphene.String(required=True)

    age = graphene.Int(required=True)

class CreatePerson(graphene.Mutation):

    class Arguments:

        person\_data = PersonInput(required=True)

    person = graphene.Field(Person)

    def mutate(root, info, person\_data=None):

        person = Person(

            name=person\_data.name,

            age=person\_data.age

        )

        return CreatePerson(person=person)

```

Note that **name** and **age** are part of **person\_data** now.

Using the above mutation your new query would look like this:

```

mutation myFirstMutation {

    createPerson(personData: {name:"Peter", age: 24}) {

        person {

            name,

            age

        }

    }

}

```

InputObjectTypes can also be fields of InputObjectTypes allowing you to have

as complex of input data as you need:

```

import graphene

class LatLngInput(graphene.InputObjectType):

    lat = graphene.Float()

    lng = graphene.Float()

#A location has a latlng associated to it

class LocationInput(graphene.InputObjectType):

    name = graphene.String()

    latlng = graphene.InputField(LatLngInput)

```

#### Output type example[¶](#output-type-example "Permalink to this headline")

To return an existing ObjectType instead of a mutation-specific type, set the **Output** attribute to the desired ObjectType:

```

import graphene

class CreatePerson(graphene.Mutation):

    class Arguments:

        name = graphene.String()

    Output = Person

    def mutate(root, info, name):

        return Person(name=name)

```

Then, if we query (`schema.execute(query\_str)`) with the following:

```

mutation myFirstMutation {

    createPerson(name:"Peter") {

        name

        \_\_typename

    }

}

```

We should receive:

```

{

    "createPerson": {

        "name": "Peter",

        "\_\_typename": "Person"

    }

}

```

Execution[¶](#execution "Permalink to this headline")

-----------------------------------------------------

### Executing a query[¶](#executing-a-query "Permalink to this headline")

For executing a query against a schema, you can directly call the `execute` method on it.

```

from graphene import Schema

schema = Schema(...)

result = schema.execute('{ name }')

```

`result` represents the result of execution. `result.data` is the result of executing the query, `result.errors` is `None` if no errors occurred, and is a non-empty list if an error occurred.

#### Context[¶](#context "Permalink to this headline")

You can pass context to a query via `context`.

```

from graphene import ObjectType, String, Schema

class Query(ObjectType):

    name = String()

    def resolve\_name(root, info):

        return info.context.get('name')

schema = Schema(Query)

result = schema.execute('{ name }', context={'name': 'Syrus'})

assert result.data['name'] == 'Syrus'

```

#### Variables[¶](#variables "Permalink to this headline")

You can pass variables to a query via `variables`.

```

from graphene import ObjectType, Field, ID, Schema

class Query(ObjectType):

    user = Field(User, id=ID(required=True))

    def resolve\_user(root, info, id):

        return get\_user\_by\_id(id)

schema = Schema(Query)

result = schema.execute(

    '''

 query getUser($id: ID) {

 user(id: $id) {

 id

 firstName

 lastName

 }

 }

 ''',

    variables={'id': 12},

)

```

#### Root Value[¶](#root-value "Permalink to this headline")

Value used for [Parent Value Object (parent)](index.html#resolverparamparent) in root queries and mutations can be overridden using `root` parameter.

```

from graphene import ObjectType, Field, Schema

class Query(ObjectType):

    me = Field(User)

    def resolve\_user(root, info):

        return {'id': root.id, 'firstName': root.name}

schema = Schema(Query)

user\_root = User(id=12, name='bob')

result = schema.execute(

    '''

 query getUser {

 user {

 id

 firstName

 lastName

 }

 }

 ''',

    root=user\_root

)

assert result.data['user']['id'] == user\_root.id

```

#### Operation Name[¶](#operation-name "Permalink to this headline")

If there are multiple operations defined in a query string, `operation\_name` should be used to indicate which should be executed.

```

from graphene import ObjectType, Field, Schema

class Query(ObjectType):

    user = Field(User)

    def resolve\_user(root, info):

        return get\_user\_by\_id(12)

schema = Schema(Query)

query\_string = '''

 query getUserWithFirstName {

 user {

 id

 firstName

 lastName

 }

 }

 query getUserWithFullName {

 user {

 id

 fullName

 }

 }

'''

result = schema.execute(

    query\_string,

    operation\_name='getUserWithFullName'

)

assert result.data['user']['fullName']

```

### Middleware[¶](#middleware "Permalink to this headline")

You can use `middleware` to affect the evaluation of fields in your schema.

A middleware is any object or function that responds to `resolve(next\_middleware, \*args)`.

Inside that method, it should either:

* Send `resolve` to the next middleware to continue the evaluation; or

* Return a value to end the evaluation early.

#### Resolve arguments[¶](#resolve-arguments "Permalink to this headline")

Middlewares `resolve` is invoked with several arguments:

* `next` represents the execution chain. Call `next` to continue evaluation.

* `root` is the root value object passed throughout the query.

* `info` is the resolver info.

* `args` is the dict of arguments passed to the field.

#### Example[¶](#example "Permalink to this headline")

This middleware only continues evaluation if the `field\_name` is not `'user'`

```

class AuthorizationMiddleware(object):

    def resolve(self, next, root, info, \*\*args):

        if info.field\_name == 'user':

            return None

        return next(root, info, \*\*args)

```

And then execute it with:

```

result = schema.execute('THE QUERY', middleware=[AuthorizationMiddleware()])

```

If the `middleware` argument includes multiple middlewares,

these middlewares will be executed bottom-up, i.e. from last to first.

#### Functional example[¶](#functional-example "Permalink to this headline")

Middleware can also be defined as a function. Here we define a middleware that

logs the time it takes to resolve each field:

```

from time import time as timer

def timing\_middleware(next, root, info, \*\*args):

    start = timer()

    return\_value = next(root, info, \*\*args)

    duration = round((timer() - start) \* 1000, 2)

    parent\_type\_name = root.\_meta.name if root and hasattr(root, '\_meta') else ''

    logger.debug(f"{parent\_type\_name}.{info.field\_name}: {duration} ms")

    return return\_value

```

And then execute it with:

```

result = schema.execute('THE QUERY', middleware=[timing\_middleware])

```

### Dataloader[¶](#dataloader "Permalink to this headline")

DataLoader is a generic utility to be used as part of your application’s

data fetching layer to provide a simplified and consistent API over

various remote data sources such as databases or web services via batching

and caching. It is provided by a separate package aiodataloader <https://pypi.org/project/aiodataloader/>.

#### Batching[¶](#batching "Permalink to this headline")

Batching is not an advanced feature, it’s DataLoader’s primary feature.

Create loaders by providing a batch loading function.

```

from aiodataloader import DataLoader

class UserLoader(DataLoader):

    async def batch\_load\_fn(self, keys):

        # Here we call a function to return a user for each key in keys

        return [get\_user(id=key) for key in keys]

```

A batch loading async function accepts a list of keys, and returns a list of `values`.

`DataLoader` will coalesce all individual loads which occur within a

single frame of execution (executed once the wrapping event loop is resolved)

and then call your batch function with all requested keys.

```

user\_loader = UserLoader()

user1 = await user\_loader.load(1)

user1\_best\_friend = await user\_loader.load(user1.best\_friend\_id))

user2 = await user\_loader.load(2)

user2\_best\_friend = await user\_loader.load(user2.best\_friend\_id))

```

A naive application may have issued *four* round-trips to a backend for the

required information, but with `DataLoader` this application will make at most *two*.

Note that loaded values are one-to-one with the keys and must have the same

order. This means that if you load all values from a single query, you must

make sure that you then order the query result for the results to match the keys:

```

class UserLoader(DataLoader):

    async def batch\_load\_fn(self, keys):

        users = {user.id: user for user in User.objects.filter(id\_\_in=keys)}

        return [users.get(user\_id) for user\_id in keys]

```

`DataLoader` allows you to decouple unrelated parts of your application without

sacrificing the performance of batch data-loading. While the loader presents

an API that loads individual values, all concurrent requests will be coalesced

and presented to your batch loading function. This allows your application to

safely distribute data fetching requirements throughout your application and

maintain minimal outgoing data requests.

#### Using with Graphene[¶](#using-with-graphene "Permalink to this headline")

DataLoader pairs nicely well with Graphene/GraphQL. GraphQL fields are designed

to be stand-alone functions. Without a caching or batching mechanism, it’s easy

for a naive GraphQL server to issue new database requests each time a field is resolved.

Consider the following GraphQL request:

```

{

  me {

    name

    bestFriend {

      name

    }

    friends(first: 5) {

      name

      bestFriend {

        name

      }

    }

  }

}

```

If `me`, `bestFriend` and `friends` each need to send a request to the backend,

there could be at most 13 database requests!

When using DataLoader, we could define the User type using our previous example with

leaner code and at most 4 database requests, and possibly fewer if there are cache hits.

```

class User(graphene.ObjectType):

    name = graphene.String()

    best\_friend = graphene.Field(lambda: User)

    friends = graphene.List(lambda: User)

    async def resolve\_best\_friend(root, info):

        return await user\_loader.load(root.best\_friend\_id)

    async def resolve\_friends(root, info):

        return await user\_loader.load\_many(root.friend\_ids)

```

### File uploading[¶](#file-uploading "Permalink to this headline")

File uploading is not part of the official GraphQL spec yet and is not natively

implemented in Graphene.

If your server needs to support file uploading then you can use the library: [graphene-file-upload](https://github.com/lmcgartland/graphene-file-upload) which enhances Graphene to add file

uploads and conforms to the unoffical GraphQL [multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec).

### Subscriptions[¶](#subscriptions "Permalink to this headline")

To create a subscription, you can directly call the `subscribe` method on the

schema. This method is async and must be awaited.

```

import asyncio

from datetime import datetime

from graphene import ObjectType, String, Schema, Field

# Every schema requires a query.

class Query(ObjectType):

    hello = String()

    def resolve\_hello(root, info):

        return "Hello, world!"

class Subscription(ObjectType):

    time\_of\_day = String()

    async def subscribe\_time\_of\_day(root, info):

        while True:

            yield datetime.now().isoformat()

            await asyncio.sleep(1)

schema = Schema(query=Query, subscription=Subscription)

async def main(schema):

    subscription = 'subscription { timeOfDay }'

    result = await schema.subscribe(subscription)

    async for item in result:

        print(item.data['timeOfDay'])

asyncio.run(main(schema))

```

The `result` is an async iterator which yields items in the same manner as a query.

### Query Validation[¶](#query-validation "Permalink to this headline")

GraphQL uses query validators to check if Query AST is valid and can be executed. Every GraphQL server implements

standard query validators. For example, there is an validator that tests if queried field exists on queried type, that

makes query fail with “Cannot query field on type” error if it doesn’t.

To help with common use cases, graphene provides a few validation rules out of the box.

#### Depth limit Validator[¶](#depth-limit-validator "Permalink to this headline")

The depth limit validator helps to prevent execution of malicious

queries. It takes in the following arguments.

* `max\_depth` is the maximum allowed depth for any operation in a GraphQL document.

* `ignore` Stops recursive depth checking based on a field name. Either a string or regexp to match the name, or a function that returns a boolean

* `callback` Called each time validation runs. Receives an Object which is a map of the depths for each operation.

#### Usage[¶](#usage "Permalink to this headline")

Here is how you would implement depth-limiting on your schema.

```

from graphql import validate, parse

from graphene import ObjectType, Schema, String

from graphene.validation import depth\_limit\_validator

class MyQuery(ObjectType):

    name = String(required=True)

schema = Schema(query=MyQuery)

# queries which have a depth more than 20

# will not be executed.

validation\_errors = validate(

    schema=schema.graphql\_schema,

    document\_ast=parse('THE QUERY'),

    rules=(

        depth\_limit\_validator(

            max\_depth=20

        ),

    )

)

```

#### Disable Introspection[¶](#disable-introspection "Permalink to this headline")

the disable introspection validation rule ensures that your schema cannot be introspected.

This is a useful security measure in production environments.

#### Usage[¶](#id1 "Permalink to this headline")

Here is how you would disable introspection for your schema.

```

from graphql import validate, parse

from graphene import ObjectType, Schema, String

from graphene.validation import DisableIntrospection

class MyQuery(ObjectType):

    name = String(required=True)

schema = Schema(query=MyQuery)

# introspection queries will not be executed.

validation\_errors = validate(

    schema=schema.graphql\_schema,

    document\_ast=parse('THE QUERY'),

    rules=(

        DisableIntrospection,

    )

)

```

#### Implementing custom validators[¶](#implementing-custom-validators "Permalink to this headline")

All custom query validators should extend the [ValidationRule](https://github.com/graphql-python/graphql-core/blob/v3.0.5/src/graphql/validation/rules/__init__.py#L37)

base class importable from the graphql.validation.rules module. Query validators are visitor classes. They are

instantiated at the time of query validation with one required argument (context: ASTValidationContext). In order to

perform validation, your validator class should define one or more of enter\_\* and leave\_\* methods. For possible

enter/leave items as well as details on function documentation, please see contents of the visitor module. To make

validation fail, you should call validator’s report\_error method with the instance of GraphQLError describing failure

reason. Here is an example query validator that visits field definitions in GraphQL query and fails query validation

if any of those fields are blacklisted:

```

from graphql import GraphQLError

from graphql.language import FieldNode

from graphql.validation import ValidationRule

my\_blacklist = (

    "disallowed\_field",

)

def is\_blacklisted\_field(field\_name: str):

    return field\_name.lower() in my\_blacklist

class BlackListRule(ValidationRule):

    def enter\_field(self, node: FieldNode, \*\_args):

        field\_name = node.name.value

        if not is\_blacklisted\_field(field\_name):

            return

        self.report\_error(

            GraphQLError(

                f"Cannot query '{field\_name}': field is blacklisted.", node,

            )

        )

```

Relay[¶](#relay "Permalink to this headline")

---------------------------------------------

Graphene has complete support for [Relay](https://relay.dev/docs/guides/graphql-server-specification/) and offers some utils to make

integration from Python easy.

### Nodes[¶](#nodes "Permalink to this headline")

A `Node` is an Interface provided by `graphene.relay` that contains

a single field `id` (which is a `ID!`). Any object that inherits

from it has to implement a `get\_node` method for retrieving a

`Node` by an *id*.

#### Quick example[¶](#quick-example "Permalink to this headline")

Example usage (taken from the [Starwars Relay example](https://github.com/graphql-python/graphene/blob/master/examples/starwars_relay/schema.py)):

```

class Ship(graphene.ObjectType):

    '''A ship in the Star Wars saga'''

    class Meta:

        interfaces = (relay.Node, )

    name = graphene.String(description='The name of the ship.')

    @classmethod

    def get\_node(cls, info, id):

        return get\_ship(id)

```

The `id` returned by the `Ship` type when you query it will be a

scalar which contains enough info for the server to know its type and

its id.

For example, the instance `Ship(id=1)` will return `U2hpcDox` as the

id when you query it (which is the base64 encoding of `Ship:1`), and

which could be useful later if we want to query a node by its id.

#### Custom Nodes[¶](#custom-nodes "Permalink to this headline")

You can use the predefined `relay.Node` or you can subclass it, defining

custom ways of how a node id is encoded (using the `to\_global\_id` method in the class)

or how we can retrieve a Node given a encoded id (with the `get\_node\_from\_global\_id` method).

Example of a custom node:

```

class CustomNode(Node):

    class Meta:

        name = 'Node'

    @staticmethod

    def to\_global\_id(type\_, id):

        return f"{type\_}:{id}"

    @staticmethod

    def get\_node\_from\_global\_id(info, global\_id, only\_type=None):

        type\_, id = global\_id.split(':')

        if only\_type:

            # We assure that the node type that we want to retrieve

            # is the same that was indicated in the field type

            assert type\_ == only\_type.\_meta.name, 'Received not compatible node.'

        if type\_ == 'User':

            return get\_user(id)

        elif type\_ == 'Photo':

            return get\_photo(id)

```

The `get\_node\_from\_global\_id` method will be called when `CustomNode.Field` is resolved.

#### Accessing node types[¶](#accessing-node-types "Permalink to this headline")

If we want to retrieve node instances from a `global\_id` (scalar that identifies an instance by it’s type name and id),

we can simply do `Node.get\_node\_from\_global\_id(info, global\_id)`.

In the case we want to restrict the instance retrieval to a specific type, we can do:

`Node.get\_node\_from\_global\_id(info, global\_id, only\_type=Ship)`. This will raise an error

if the `global\_id` doesn’t correspond to a Ship type.

#### Node Root field[¶](#node-root-field "Permalink to this headline")

As is required in the [Relay specification](https://facebook.github.io/relay/docs/graphql-relay-specification.html), the server must implement

a root field called `node` that returns a `Node` Interface.

For this reason, `graphene` provides the field `relay.Node.Field`,

which links to any type in the Schema which implements `Node`.

Example usage:

```

class Query(graphene.ObjectType):

    # Should be CustomNode.Field() if we want to use our custom Node

    node = relay.Node.Field()

```

### Connection[¶](#connection "Permalink to this headline")

A connection is a vitaminized version of a List that provides ways of

slicing and paginating through it. The way you create Connection types

in `graphene` is using `relay.Connection` and `relay.ConnectionField`.

#### Quick example[¶](#quick-example "Permalink to this headline")

If we want to create a custom Connection on a given node, we have to subclass the

`Connection` class.

In the following example, `extra` will be an extra field in the connection,

and `other` an extra field in the Connection Edge.

```

class ShipConnection(Connection):

    extra = String()

    class Meta:

        node = Ship

    class Edge:

        other = String()

```

The `ShipConnection` connection class, will have automatically a `pageInfo` field,

and a `edges` field (which is a list of `ShipConnection.Edge`).

This `Edge` will have a `node` field linking to the specified node

(in `ShipConnection.Meta`) and the field `other` that we defined in the class.

#### Connection Field[¶](#connection-field "Permalink to this headline")

You can create connection fields in any Connection, in case any ObjectType

that implements `Node` will have a default Connection.

```

class Faction(graphene.ObjectType):

    name = graphene.String()

    ships = relay.ConnectionField(ShipConnection)

    def resolve\_ships(root, info):

        return []

```

### Mutations[¶](#mutations "Permalink to this headline")

Most APIs don’t just allow you to read data, they also allow you to

write.

In GraphQL, this is done using mutations. Just like queries,

Relay puts some additional requirements on mutations, but Graphene

nicely manages that for you. All you need to do is make your mutation a

subclass of `relay.ClientIDMutation`.

```

class IntroduceShip(relay.ClientIDMutation):

    class Input:

        ship\_name = graphene.String(required=True)

        faction\_id = graphene.String(required=True)

    ship = graphene.Field(Ship)

    faction = graphene.Field(Faction)

    @classmethod

    def mutate\_and\_get\_payload(cls, root, info, \*\*input):

        ship\_name = input.ship\_name

        faction\_id = input.faction\_id

        ship = create\_ship(ship\_name, faction\_id)

        faction = get\_faction(faction\_id)

        return IntroduceShip(ship=ship, faction=faction)

```

#### Accepting Files[¶](#accepting-files "Permalink to this headline")

Mutations can also accept files, that’s how it will work with different integrations:

```

class UploadFile(graphene.ClientIDMutation):

     class Input:

         pass

         # nothing needed for uploading file

     # your return fields

     success = graphene.String()

    @classmethod

    def mutate\_and\_get\_payload(cls, root, info, \*\*input):

        # When using it in Django, context will be the request

        files = info.context.FILES

        # Or, if used in Flask, context will be the flask global request

        # files = context.files

        # do something with files

        return UploadFile(success=True)

```

### Useful links[¶](#useful-links "Permalink to this headline")

* [Getting started with Relay](https://relay.dev/docs/getting-started/step-by-step-guide/)

* [Relay Global Identification Specification](https://relay.dev/graphql/objectidentification.htm)

* [Relay Cursor Connection Specification](https://relay.dev/graphql/connections.htm)

Testing in Graphene[¶](#testing-in-graphene "Permalink to this headline")

-------------------------------------------------------------------------

Automated testing is an extremely useful bug-killing tool for the modern developer. You can use a collection of tests – a test suite – to solve, or avoid, a number of problems:

* When you’re writing new code, you can use tests to validate your code works as expected.

* When you’re refactoring or modifying old code, you can use tests to ensure your changes haven’t affected your application’s behavior unexpectedly.

Testing a GraphQL application is a complex task, because a GraphQL application is made of several layers of logic – schema definition, schema validation, permissions and field resolution.

With Graphene test-execution framework and assorted utilities, you can simulate GraphQL requests, execute mutations, inspect your application’s output and generally verify your code is doing what it should be doing.

### Testing tools[¶](#testing-tools "Permalink to this headline")

Graphene provides a small set of tools that come in handy when writing tests.

#### Test Client[¶](#test-client "Permalink to this headline")

The test client is a Python class that acts as a dummy GraphQL client, allowing you to test your views and interact with your Graphene-powered application programmatically.

Some of the things you can do with the test client are:

* Simulate Queries and Mutations and observe the response.

* Test that a given query request is rendered by a given Django template, with a template context that contains certain values.

#### Overview and a quick example[¶](#overview-and-a-quick-example "Permalink to this headline")

To use the test client, instantiate `graphene.test.Client` and retrieve GraphQL responses:

```

from graphene.test import Client

def test\_hey():

    client = Client(my\_schema)

    executed = client.execute('''{ hey }''')

    assert executed == {

        'data': {

            'hey': 'hello!'

        }

    }

```

#### Execute parameters[¶](#execute-parameters "Permalink to this headline")

You can also add extra keyword arguments to the `execute` method, such as

`context`, `root`, `variables`, ...:

```

from graphene.test import Client

def test\_hey():

    client = Client(my\_schema)

    executed = client.execute('''{ hey }''', context={'user': 'Peter'})

    assert executed == {

        'data': {

            'hey': 'hello Peter!'

        }

    }

```

#### Snapshot testing[¶](#snapshot-testing "Permalink to this headline")

As our APIs evolve, we need to know when our changes introduce any breaking changes that might break

some of the clients of our GraphQL app.

However, writing tests and replicating the same response we expect from our GraphQL application can be a

tedious and repetitive task, and sometimes it’s easier to skip this process.

Because of that, we recommend the usage of [SnapshotTest](https://github.com/syrusakbary/snapshottest/).

SnapshotTest lets us write all these tests in a breeze, as it automatically creates the `snapshots` for us

the first time the test are executed.

Here is a simple example on how our tests will look if we use `pytest`:

```

def test\_hey(snapshot):

    client = Client(my\_schema)

    # This will create a snapshot dir and a snapshot file

    # the first time the test is executed, with the response

    # of the execution.

    snapshot.assert\_match(client.execute('''{ hey }'''))

```

If we are using `unittest`:

```

from snapshottest import TestCase

class APITestCase(TestCase):

    def test\_api\_me(self):

        """Testing the API for /me"""

        client = Client(my\_schema)

        self.assertMatchSnapshot(client.execute('''{ hey }'''))

```

API Reference[¶](#api-reference "Permalink to this headline")

-------------------------------------------------------------

### Schema[¶](#schema "Permalink to this headline")

### Object types[¶](#object-types "Permalink to this headline")

### Fields (Mounted Types)[¶](#fields-mounted-types "Permalink to this headline")

### Fields (Unmounted Types)[¶](#fields-unmounted-types "Permalink to this headline")

### GraphQL Scalars[¶](#graphql-scalars "Permalink to this headline")

### Graphene Scalars[¶](#graphene-scalars "Permalink to this headline")

### Enum[¶](#enum "Permalink to this headline")

### Structures[¶](#structures "Permalink to this headline")

### Type Extension[¶](#type-extension "Permalink to this headline")

### Execution Metadata[¶](#execution-metadata "Permalink to this headline")

Integrations[¶](#integrations "Permalink to this headline")

-----------------------------------------------------------

* [Graphene-Django](http://docs.graphene-python.org/projects/django/en/latest/) ([source](https://github.com/graphql-python/graphene-django/))

* Flask-Graphql ([source](https://github.com/graphql-python/flask-graphql))

* [Graphene-SQLAlchemy](http://docs.graphene-python.org/projects/sqlalchemy/en/latest/) ([source](https://github.com/graphql-python/graphene-sqlalchemy/))

* [Graphene-GAE](http://docs.graphene-python.org/projects/gae/en/latest/) ([source](https://github.com/graphql-python/graphene-gae/))

* [Graphene-Mongo](http://graphene-mongo.readthedocs.io/en/latest/) ([source](https://github.com/graphql-python/graphene-mongo))

* [Starlette](https://www.starlette.io/graphql/) ([source](https://github.com/encode/starlette))

* [FastAPI](https://fastapi.tiangolo.com/advanced/graphql/) ([source](https://github.com/tiangolo/fastapi))

