<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Data Hustle]]></title><description><![CDATA[Tech is only as valuable as you can sell it. The Data Hustle is your guide to mastering the art of communicating data’s impact. Focused on highlighting the value provided by data, technology and adjacent fields to business, customers, society.]]></description><link>https://www.blog.zelytics.tech</link><image><url>https://substackcdn.com/image/fetch/$s_!-Qqq!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a2be1f9-ee35-4ed2-802e-c7371876df64_1200x1200.png</url><title>The Data Hustle</title><link>https://www.blog.zelytics.tech</link></image><generator>Substack</generator><lastBuildDate>Wed, 13 May 2026 05:39:13 GMT</lastBuildDate><atom:link href="https://www.blog.zelytics.tech/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Tony Zeljkovic]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[tonyzeljkovic@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[tonyzeljkovic@substack.com]]></itunes:email><itunes:name><![CDATA[Tony Zeljkovic]]></itunes:name></itunes:owner><itunes:author><![CDATA[Tony Zeljkovic]]></itunes:author><googleplay:owner><![CDATA[tonyzeljkovic@substack.com]]></googleplay:owner><googleplay:email><![CDATA[tonyzeljkovic@substack.com]]></googleplay:email><googleplay:author><![CDATA[Tony Zeljkovic]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Data Hustle #3: Knowledge Driven Development]]></title><description><![CDATA[Some musings on software 3.0]]></description><link>https://www.blog.zelytics.tech/p/knowledge-driven-development</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/knowledge-driven-development</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Fri, 11 Jul 2025 14:39:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!-Qqq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a2be1f9-ee35-4ed2-802e-c7371876df64_1200x1200.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let&#8217;s be honest.</p><p>When things started out with ChatGPT 3 years ago (It has only been three years ago?!), many people were pretending not to use it. </p><p>As things progressed, quite quickly, engineers would &#8220;leave it in the middle&#8221; whether they were using AI and how.</p><p>Now that we are seeing tooling for LLM-assisted code development gain popularity with copilot, cursor and windsurf, there&#8217;s no more dilly dallying around it:</p><blockquote><p><strong>Most all engineers are using AI in their workflows.</strong></p></blockquote><p>So, why do our code bases then not reflect this reality yet?</p><div class="pullquote"><p><strong>DISCLAIMER</strong></p><p>I just want to preface this article with all the objections against an article like this:</p><p>This is <strong>NOT</strong> to say AI will overtake all software development.</p><p>This is <strong>NOT</strong> to say we should always be prompting for every software solution we write.</p><p>This does <strong>NOT</strong> mean we don&#8217;t have to put in time and effort into our designs and work on code iteratively <strong>WITHOUT</strong> AI.</p><p>This is to say that when we <strong>DO</strong> use AI, we should actually put in some work to use it as an effective tool for whatever we are doing.</p></div><p>Now that we got that out of the way, let&#8217;s get into it.</p><h1>A new era of software engineering: Prompt Engineering?</h1><p>Two weeks ago, Andrej Karpathy had some fascinating insights in his recent Y-combinator talk on how &#8220;software is changing again&#8221;.</p><div id="youtube2-LCEmiRjPEtQ" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;LCEmiRjPEtQ&quot;,&quot;startTime&quot;:&quot;1898s&quot;,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/LCEmiRjPEtQ?start=1898s&amp;rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>In one part he was describing how the code base for self-driving evolved in tesla into roughly three paradigms:</p><p><strong>Software 1.0</strong> &#8212; Classical software.</p><p><strong>Software 2.0</strong> &#8212; The training and weighing of neural nets.</p><p><strong>Software 3.0</strong> &#8212; Prompts to the trained neural nets.</p><p>It has really struck me that the archetype of the codebase as a whole was changing and I think we can draw parallels into code bases as a whole in the industry in the years to come.</p><p>That got me to think however: what <strong>IS</strong> the best way to deal with Software 3.0 or prompts in a code base?</p><h1>Everyone is talking to LLMs in isolation</h1><p>Let&#8217;s take a step back and zoom out a bit.</p><p>Let&#8217;s say we have a code base for our team and we have 10 engineers that are prompting the LLM on the same code base to develop features for it.</p><p>How much time do you spend on refining your prompts and explaining your code base to an LLM?</p><p>Anyone who has put serious time into these will say: &#8220;<strong>A lot</strong>&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ehU6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ehU6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!ehU6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!ehU6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!ehU6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ehU6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/35629482-16b8-40af-b1dc-361d59362d20_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1681569,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ehU6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!ehU6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!ehU6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!ehU6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35629482-16b8-40af-b1dc-361d59362d20_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">POV aggravated senior software engineer at prompt 50 in their LLM conservation</figcaption></figure></div><p>Obviously, this improves with:</p><ul><li><p>Every new iteration of AI models</p></li><li><p>Larger context windows </p></li><li><p>Smart tricks like code editors indexing your code base to understand it&#8217;s structure </p></li></ul><p>&#8212; but that doesn&#8217;t mean that it will tackle the problem at hand in the most efficient way given current constraints.</p><p>In my own testing of this, I&#8217;ve seen this can go wrong in a couple of ways in practise. Some examples:</p><ul><li><p>There are multiple legacy patterns in the code base that need to be ignored for certain pieces of code, but not for others.</p></li><li><p>The LLM (like a human) might try to take a shortcut and write a one-off solution that is not congruent with the pattern within the code base.</p></li><li><p>Having more irrelevant context decreases the amount of relevant context available for my query</p></li><li><p>Too much context can confuse models</p></li></ul><p>The cost of this is quite significant.</p><p><strong>If we</strong> <strong>know</strong> for a fact that engineers will be using LLMs for development<br><strong>if we</strong> <strong>know</strong> that engineering hours are <strong>expensive</strong><br><strong>Then we need to</strong> <strong>acknowledge</strong> the fact that if we don&#8217;t optimize for their interactions with an LLM we are losing valuable resources in time and effort.</p><blockquote><p>hours wasted prompting LLMs = Wasted Engineering hours = &#128184;&#128184;&#128184;</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pWJp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pWJp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!pWJp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!pWJp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!pWJp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pWJp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:182402,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pWJp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!pWJp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!pWJp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!pWJp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd96572e-36dc-43df-bf17-6254c6d56f09_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The engineering team burning their billable hours and AI credits on the same prompts.</figcaption></figure></div><p>Do you really want all the engineers in a team reinventing the wheel every time when it comes to how they work with the LLM on more repetitive and predictable parts of a code base?</p><p>There has been some development in the field to fine-tune these sorts of issues.</p><p>Tools like cursor introduce the concept of <a href="https://docs.cursor.com/context/rules">rules</a> which are reusable instructions that can be applied selectively based on user input, location of a file in a code base and more. Others like GitHub implemented <a href="https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/context/managing-copilot-knowledge-bases">organization wide knowledge bases</a> that can be used by LLM coding agents in the IDE.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IwCo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IwCo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 424w, https://substackcdn.com/image/fetch/$s_!IwCo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 848w, https://substackcdn.com/image/fetch/$s_!IwCo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!IwCo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IwCo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png" width="1456" height="1009" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1009,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:104037,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/167902125?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IwCo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 424w, https://substackcdn.com/image/fetch/$s_!IwCo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 848w, https://substackcdn.com/image/fetch/$s_!IwCo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!IwCo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58a1fcee-f85d-4e5a-b98b-141bb9eab787_1630x1130.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A simplified overview of context we may provide as engineers within a single session to the LLM (excluding things like web searches, and internal redirects).</figcaption></figure></div><p>There is still work to be done on how knowledge and prompts will be organized in code bases &#8212; that is a given &#8212; but the concept of how to actually properly build and integrate this knowledge is a topic that will stay relevant no matter what technology will be deployed.</p><p>With that, there is a fundamental psychological change needed when it comes to developing and maintaining code as a team which I would like to coin as &#8220;<strong>knowledge driven development</strong>&#8221;.</p><blockquote><p>Knowledge driven development is a development paradigm that prioritizes the  structuring, curating and generation of context for AI and for humans in a code base.</p></blockquote><p>For the purposes of this article, I will (mostly) not be going over knowledge basis but rather human crafted prompts and context.</p><p>Well then, let&#8217;s take a look at what that might look like in practise and the potential longer term ramifications of that.</p><h1>Documentation re-envisioned: Prompt context as documentation</h1><p>Once we reach a certain complexity in a code base, we all know that &#8220;just reading the code&#8221; to understand how everything ties together becomes increasingly complicated.</p><p>There is also the fact that as a code base grows in importance, the amount of engineers that will interact with it over time increases significantly.</p><p>As the amount of people interacting with the code base and each other grows, the maximum amount of social relationships and interactions grows quite aggresively:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;C = n(n-1)/2&quot;,&quot;id&quot;:&quot;MTHXHQBEKX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where C stands for the total connections in the social network and n the amount of nodes in the network.</p><blockquote><p>Large code projects don&#8217;t just break on code complexity, they break on failures of communication at scale.</p></blockquote><p>We all know documentation is always a significant challenge when it comes to maintaining a large code base. Not necessarily because it&#8217;s hard but because incentives are not aligned.</p><p>Why would you write documentation if that is not rewarded from an organizational perspective? How do you justify spending time on documentation that you could be spending on building new features for the business?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!12AR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!12AR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!12AR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!12AR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!12AR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!12AR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif" width="480" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1173981,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!12AR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!12AR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!12AR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!12AR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9f87f40-5680-44dc-8a8b-21ce4bdf7163_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Engineers being tasked with documenting their code.</figcaption></figure></div><p>Now what happens if we define our documentation in a code base in the form of prompts / knowledge in our codebase.</p><p>Let&#8217;s say for theoretical purposes we have a simple modular code base. Let&#8217;s say we have a few system wide prompts that engineers can use, as well as prompts that are specific to the modules and stored within them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xmXa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xmXa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 424w, https://substackcdn.com/image/fetch/$s_!xmXa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 848w, https://substackcdn.com/image/fetch/$s_!xmXa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 1272w, https://substackcdn.com/image/fetch/$s_!xmXa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xmXa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png" width="1456" height="1083" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1083,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:298615,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/167902125?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xmXa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 424w, https://substackcdn.com/image/fetch/$s_!xmXa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 848w, https://substackcdn.com/image/fetch/$s_!xmXa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 1272w, https://substackcdn.com/image/fetch/$s_!xmXa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bea2fdb-1427-4a49-b01b-24290da836b8_1874x1394.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Simplified overview of system wide prompts versus module specific prompts.</figcaption></figure></div><p>This does two things now.</p><ol><li><p>A different engineer (perhaps a junior engineer) can read in plain english what the design and architecture of the codebase and modules is.</p></li><li><p>Engineers already familiar with the code base using LLMs for development can use these prompts when developing new features to get their LLM workflow to spit out the correct answer faster.</p></li></ol><p>You see how documentation suddenly is more aligned with different incentives in the team?</p><p>We can now start to formalise in natural language what feature development in our code base ought to look like.</p><p>When I was a more junior engineer, I would learn a lot by observing the language used by more senior engineers. Whether it was:</p><ul><li><p>a technology (e.g snowflake)</p></li><li><p>a development style (e.g test driven development)</p></li><li><p>a software design pattern (low-coupling)</p></li><li><p>an architecture (microservices)</p></li></ul><p>Just being exposed to the language gave me the tools to ask better question to grow faster as an engineer. It gets engineers unfamiliar with the field much more quickly from an <strong>unkown unkown</strong> state to a <strong>known unknown</strong> state which is very powerful for learning.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BNps!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BNps!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 424w, https://substackcdn.com/image/fetch/$s_!BNps!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 848w, https://substackcdn.com/image/fetch/$s_!BNps!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 1272w, https://substackcdn.com/image/fetch/$s_!BNps!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BNps!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png" width="1456" height="645" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:645,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:149682,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/167902125?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BNps!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 424w, https://substackcdn.com/image/fetch/$s_!BNps!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 848w, https://substackcdn.com/image/fetch/$s_!BNps!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 1272w, https://substackcdn.com/image/fetch/$s_!BNps!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21046f45-c8c4-4592-aea4-dd41cc3f58b7_2596x1150.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">It is much faster to learn about known unknowns than unknown unkowns</figcaption></figure></div><p>Encoding these principles in well written prompts in the code base allows me to guide junior engineers faster through the learning process &#8212; perhaps we can even use this context to help them start a conversation with the LLM. For example one could create a prompt</p><blockquote><p>Explain to me what it means for the code base to have &lt;x attribute&gt; and show me example in the current code base highlighting these principles.</p></blockquote><p>Alright sure but how do we get a nexus of prompts into our code base you may ask?</p><h1>CI/CD and prompts and code reviews</h1><p>If we acknowledge that context is vital in a code base, this has to change our perspective to how we do code review and deploy new code.</p><p>Similarly to how one would require the inclusion of tests in a code base when developing a new feature, we should require a Pull Request to include the addition or modification of context and changes in the code base.</p><p>The best way to encode such a practise in CI/CD is still debatable but it&#8217;s possible to start small.</p><p>Whenever you&#8217;ve developed a new feature for a code base, simply have the LLM summarize your conversation, the learnings and what-not into crystallized rules and context for future conversations and commit these to version control.</p><blockquote><p>Whenever a new pattern is added to the code base or a new module is introduced, a requirement in scoping <strong>SHOULD</strong> include the context provided to LLMs and humans in the code base.</p></blockquote><p>Another thing to consider about prompts is having LLMs as code reviewers of pull requests.</p><p>We are now seeing the emergence of LLM driven code reviewing tools either as SaaS products or as part of CI/CD pipelines within organizations.</p><p>Let&#8217;s take a step back.</p><p>What makes a code review a good code review anyway?</p><p>We will all have different answers and preferences that are strongly influenced by the code base, the team, the organization, the industry and a whole lot more.</p><p>If I work in a strongly regulated industry like healthcare for example, I might want to have more critical review when it comes to compliance in accordance to say HIPAA/HITECH.</p><p>What else makes a code review good?</p><p>Getting the perspective from different kinds of developers with different styles, preferences, and expertise tend to improve the quality of the review.</p><p>With this in mind, we could create developer personas out of prompts and rules and we can use these to scale and enhance reviews from different kinds of engineers.</p><p>If for example, we have a security team in an organization that is stretched thin but still wants to verify and question specific components of all the pull request coming into an organization, that team can write the context and prompts for their developer persona and we would be able to integrate this perspective automatically in an AI.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rPnl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rPnl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 424w, https://substackcdn.com/image/fetch/$s_!rPnl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 848w, https://substackcdn.com/image/fetch/$s_!rPnl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 1272w, https://substackcdn.com/image/fetch/$s_!rPnl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rPnl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif" width="480" height="328" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:328,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4288538,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rPnl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 424w, https://substackcdn.com/image/fetch/$s_!rPnl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 848w, https://substackcdn.com/image/fetch/$s_!rPnl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 1272w, https://substackcdn.com/image/fetch/$s_!rPnl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f94c346-1173-49b0-932b-361f0f111b0a_480x328.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The army of PR review bots waiting to review your PRs</figcaption></figure></div><p>Still, it might be a lot of work to write context and prompts from scratch which is why it would be a good idea to consider other ways to generate these contexts as well.</p><h1>Creating organizational knowledge out of documents</h1><p>Most large software organizations will have tons of design documents, feature specifications and requirements lying around that were used to start developing features in their code base. Why don&#8217;t we use these as input to create appropriate context in a code repository?</p><p>There&#8217;s actually a wide plethora of context produced in an organization in meetings, notes, docs, you name it.</p><p>The question becomes: are you integrating and using this as effectively as possible?</p><p>It&#8217;s possible for example to process documents and create vector databases out of them storing the knowledge as embeddings.</p><p>These embeddings can be the basis of an simple AI agentic workflow that take these inputs from across the organization and produce valuable context and documentation that can be used and version controlled in a code repository for future work and reference.</p><p>Okay, we&#8217;ve talked a bunch about collecting input for prompts but how should we actually model them in our code base?</p><h1>Prompt modeling</h1><p>One of the questions on prompts would be how to model them at scale in a code base / organization. While there are no good answers or frameworks yet, some of the question that came up for me are:</p><ol><li><p>What sort of prompt are we storing?</p><ol><li><p>Is this a style guide?</p></li><li><p>Is this external context? (e.g docs, syntax)</p></li><li><p>Is this prompt part of the application?</p></li><li><p>Is this prompt part of the development flow?</p></li><li><p>Is this prompt meant for creative exploration?</p></li><li><p>Is this prompt meant for critical feedback?</p></li></ol></li><li><p>What is the metadata we want to store around our prompt?</p><ol><li><p>What model and settings did we use for this prompt?</p></li><li><p>How long or short should our prompt be? (<a href="https://docs.cursor.com/context/rules#best-practices">Cursor for example suggest &lt; 500 lines for a rule</a>)</p></li><li><p>How &#8220;complex&#8221; is our prompt?</p></li><li><p>How &#8220;vague&#8221; is our prompt?</p></li><li><p>How do we label a prompt?</p></li></ol></li><li><p>What overall structure do we maintain?</p><ol><li><p>Do we have a flat structure of composable rules or do we allow hierarchy?</p></li><li><p>Do we store context in a central location, spread throughout the code base or do we have a separate repository altogether?</p></li></ol></li></ol><p>This is by no means an exhaustive list but in future posts and development in the field, it would definitely be interesting to think through the &#8220;meta&#8221; layer of this all.</p><h1>Prisoners Dilemma in prompt sharing?</h1><p>There&#8217;s an obvious catch to all of this prompt sharing. If a LLM-savvy engineer has a really effective personal system with highly effective customized prompts, custom context, etc, do they even want to be sharing their setup across an organization?</p><p>If one has a team with engineers that hold a zero-sum perspective that can create a classical <a href="https://en.wikipedia.org/wiki/Prisoner%27s_dilemma">prisoners dilemma</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TLKi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TLKi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 424w, https://substackcdn.com/image/fetch/$s_!TLKi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 848w, https://substackcdn.com/image/fetch/$s_!TLKi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 1272w, https://substackcdn.com/image/fetch/$s_!TLKi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TLKi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png" width="1456" height="758" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:758,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:379438,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/167902125?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TLKi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 424w, https://substackcdn.com/image/fetch/$s_!TLKi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 848w, https://substackcdn.com/image/fetch/$s_!TLKi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 1272w, https://substackcdn.com/image/fetch/$s_!TLKi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa08f9df0-84a4-4470-8bc2-21ccd3e8b1fe_2048x1066.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Let&#8217;s say we have an engineer A and B.</p><p>The organization decides to store and share prompts and context but both engineers have a personal choice as to how far they commit into this.</p><p>If we assume that both engineers have unique assets that can yield improved productivity and they do not talk honestly to each other, a funny situation arises.</p><p>If one engineer can have other engineers share all their knowledge but keep their unique assets to themselves, they could theoretically gain an asymmetrical advantage and create a wider margin in code output over other engineers output.</p><p>This changes drastically however if we measure ones impact on total output by the team.</p><p>In a more healthy team dynamic, what drives the impact of a senior+ engineer is not their individual output but their ability to lift and rise other engineers as a whole.</p><p>Making 10 other engineers 2x more productive makes you a 20X engineer, which is far better than being a 10X engineer all by yourself alone.</p><p>Now even if we have a healthy team dynamic, there is another big important question when it comes to sharing context: Who finally owns this all?</p><h1>AI instructions: Fair use or intellectual property</h1><p>If we consider prompt to actually be part of a code base what does this mean for the intellectual property in a a code base?</p><p>In software 1.0, intellectual property would be within the systems the organization as a whole has.</p><p>In software 2.0, the intellectual property might be the LLM and it&#8217;s weights (which is still a topic of much debate)</p><p>In software 3.0 however&#8230;.english text is intellectual property of the organization?</p><p>Let&#8217;s try to extrapolate to a (possible) future where there is actually a ton of prompts and context defined for LLMs across code bases, either as part of the application or as part of the development experience.</p><p>Where do we draw the line of what is intellectual property of the organization and what is fair use outside of it?</p><p>If 20% of your code base is instructions for an AI, can&#8217;t we rule that it&#8217;s a crucial part of the application and therefore property of the firm?</p><p>Is the prompt valuable enough to even consider property or will this reduce in importance in future iterations of LLMs?</p><p>It&#8217;s a pretty funny twist in irony &#8212; AI tools scrape the internet and all of its intellectual property in it but then we claim intellectual property on it&#8217;s weights and the prompts.</p>]]></content:encoded></item><item><title><![CDATA[Data Hustle #2: Breaking Free from RBAC: Why Your Data Warehouse Needs Attribute-Based Access Control (ABAC)]]></title><description><![CDATA[The rise of the ABAC!]]></description><link>https://www.blog.zelytics.tech/p/data-hustle-2-breaking-free-from</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/data-hustle-2-breaking-free-from</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Fri, 27 Jun 2025 17:46:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!-Qqq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a2be1f9-ee35-4ed2-802e-c7371876df64_1200x1200.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p><em>"Your data team just got a Slack message at 3 AM: 'Why can the intern see customer SSNs?' Welcome to the wonderful world of RBAC sprawl."</em></p></blockquote><p>Anyone working with large Snowflake data warehouses eventually hits the same wall: Role-Based Access Control doesn't scale with modern data complexity.</p><p>What starts as a simple "give Sarah access to the customer table" spirals into creating <strong>role_customer_readonly_q4_marketing_manager_aggregate_unless_emergency_then_full_access</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HqW7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HqW7!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 424w, https://substackcdn.com/image/fetch/$s_!HqW7!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 848w, https://substackcdn.com/image/fetch/$s_!HqW7!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 1272w, https://substackcdn.com/image/fetch/$s_!HqW7!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HqW7!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif" width="480" height="204" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:204,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7647166,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!HqW7!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 424w, https://substackcdn.com/image/fetch/$s_!HqW7!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 848w, https://substackcdn.com/image/fetch/$s_!HqW7!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 1272w, https://substackcdn.com/image/fetch/$s_!HqW7!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54569ebe-5f7a-4a43-8d5b-e37984e7eebe_480x204.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Data Platform engineer trying to explain the role hierarchy of the organization.</figcaption></figure></div><p>If this sounds familiar, you've crashed into the limitations every data team faces when managing thousands of dbt models across multiple environments.</p><p>This article dives into the practical reality of implementing Attribute-Based Access Control (ABAC) in a modern data warehouse - specifically Snowflake + dbt. I'll walk through the design principles you need to consider when developing a system like this. What will become apparent is that although the tooling exists, implementing this properly remains a complex effort in today's technical landscape.</p><h2>Why RBAC Breaks Down at Scale</h2><p>Let's look at what's actually happening in your data warehouse right now.</p><p>Classical RBAC works fine when you have 10 tables and 5 users. It breaks down spectacularly when you're managing thousands of views and tables across multiple data marts, dynamic DAG-based transformations, column and row-level permissions that change based on user context, and business requirements that shift faster than your deployment pipeline.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FxxH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FxxH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!FxxH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!FxxH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!FxxH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FxxH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif" width="480" height="270" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1517621,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!FxxH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!FxxH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!FxxH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!FxxH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed982a83-8eea-424e-b35c-d29e305ebf7d_480x270.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Data Platform Engineer when they are requested to create another 500 roles for access control on snowflake</figcaption></figure></div><p>With traditional RBAC, every permission request flows through your data platform team.</p><p>&#10067;Want access to the new customer churn model?</p><p>&#128229; Submit a ticket.</p><p>&#10067; Need to see revenue data but only for your region?</p><p>&#128229;  Another ticket.</p><p>&#128584; Your data team becomes a permission factory full of permission monkeys.</p><p><strong>It's not uncommon for my clients to have 10-20% of their data tickets related to access requests in some way, shape, or form</strong>. As the number of models and end-users consuming data grows, the potential access permutations grow exponentially.</p><p>Modern data transformation tools make this even more painful. </p><p>dbt operates on DAG-based selectors - you can easily target "all models tagged with 'marketing'" or "everything downstream of dim_customers." </p><p>But try doing that with traditional roles? Good luck.</p><p>ABAC changes this entirely. Instead of pre-defining every possible role combination, you define attributes and let the system dynamically determine access patterns.</p><p>The scenarios where ABAC becomes essential include multi-tenant SaaS platforms where different customers see only their data with admin overrides, healthcare HIPAA compliance where access varies by role, department, and patient relationship, and financial services with regulatory requirements that change based on user location and data sensitivity.</p><h2>Building ABAC on Snowflake</h2><p>Let's look at what implementing this actually involves.</p><h3>Dynamic Masking and Column-Level Security</h3><p>Before diving into tag-based implementation, you need to understand when to use row access policies versus column masking policies - they serve different purposes. Row access policies control which rows a user can see entirely, while column masking policies transform the data within visible columns at query time. Think of row access as "can this user see this customer's record at all?" versus column masking as "this user can see the customer record, but only a masked version of their credit card number."</p><p>Tag-based masking combines Snowflake's object tagging and masking policy features, allowing a masking policy to be set on a tag using an ALTER TAG command. When the data type in the masking policy signature matches the column's data type, tagged columns are automatically protected. This eliminates the need to manually apply masking policies to every single column containing sensitive data.</p><p>Here's how this works in practice:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Pfvu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pfvu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 424w, https://substackcdn.com/image/fetch/$s_!Pfvu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 848w, https://substackcdn.com/image/fetch/$s_!Pfvu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 1272w, https://substackcdn.com/image/fetch/$s_!Pfvu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pfvu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png" width="1456" height="904" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:904,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:666642,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/166972585?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Pfvu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 424w, https://substackcdn.com/image/fetch/$s_!Pfvu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 848w, https://substackcdn.com/image/fetch/$s_!Pfvu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 1272w, https://substackcdn.com/image/fetch/$s_!Pfvu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F673d7527-36ce-4410-9009-bd2a3bcc7fb0_3596x2232.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Example of using tag based dynamic data masking policies.</figcaption></figure></div><p>Tag-based policies allow administrators to write a policy once, assign it to a tag once, and have the policy apply to many objects automatically. No more manually tracking down every email column across hundreds of tables.</p><h3>Managing Policies and Sub-Policies</h3><p>Each tag can support one masking policy per data type - if a tag already has a masking policy for VARCHAR, you cannot assign another VARCHAR masking policy to the same tag. </p><p>This constraint forces you to think strategically about your tag architecture. You might need separate tags like <code>pii_email_internal</code> and <code>pii_email_external</code> rather than trying to handle all email masking with a single tag.</p><p>Most teams underestimate the complexity required for production-ready masking. "Mask or no mask" thinking will leave you with security gaps and broken test environments. You need granular masking strategies that consider both security requirements and operational needs.</p><p>Every single Snowflake data type needs a policy - VARCHAR, NUMBER, DATE, TIMESTAMP, VARIANT. Miss one, and you have a security gap.</p><h3>The Attribute Data Model</h3><p>This is where things get more abstract.</p><p>Your attribute model determines everything else. </p><p>Binary access (masked/unmasked) is just the starting point. </p><p>You need to consider things like:</p><ul><li><p>Do we organize by business unit?</p></li><li><p>By functional role?</p></li><li><p>By data mart?</p></li><li><p>By data lineage?</p></li></ul><p>Here's another thing most teams miss when implementing this in the BI layer: you need a dedicated role per user for the BI layer. Each user connects through their individual role, and each role must be defined within at least one group. </p><h3>State Management Between dbt and Snowflake</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yIUe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yIUe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 424w, https://substackcdn.com/image/fetch/$s_!yIUe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 848w, https://substackcdn.com/image/fetch/$s_!yIUe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!yIUe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yIUe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg" width="717" height="421.8294930875576" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:383,&quot;width&quot;:651,&quot;resizeWidth&quot;:717,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!yIUe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 424w, https://substackcdn.com/image/fetch/$s_!yIUe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 848w, https://substackcdn.com/image/fetch/$s_!yIUe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!yIUe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a59043e-0f8a-4f0a-a6cc-d8b3f2890145_651x383.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Now it gets gnarly.</figcaption></figure></div><p>You're managing two sources of truth: your dbt graph with tags and configurations, and the Snowflake production environment with actual applied policies. Treat dbt as your "plan" and Snowflake as the environment that must match. This infrastructure-as-code mindset prevents configuration drift.</p><p>Then there is a painful truth in dbt.</p><p>DBT is very permissible when it comes to yaml structures, a bit too permissible.</p><p>&#10071;&#65039;What happens if a model is not defined in a yaml?</p><p>&#10071;&#65039;What happens if all columns aren&#8217;t defined?</p><p>&#10071;&#65039;What happens if data is removed?</p><p>&#10071;&#65039;What happens if data types change?</p><p>and so forth.</p><p>Your team must build automations that fills in default tags based on model location, naming conventions, or lineage position.</p><blockquote><p> If you're going to automate tag management, use <a href="https://yaml.dev/doc/ruamel.yaml/">ruamel.yaml</a> - it preserves comments and formatting when modifying dbt model YAML files programmatically.</p></blockquote><p>Then there&#8217;s process questions.</p><p>Who actually maintains these policies day-to-day?</p><p>Who determines whether a user should be part of the group?</p><p>How often are groups evaluated?</p><p>Most teams underestimate this operational overhead. </p><h3>Some more practical things around applying tags</h3><p>For complete masking coverage, you cannot deploy models directly to production. Use staging tables with policy application, then atomic swaps. Any gap between model deployment and policy application means unmasked data exposure.</p><p>While Snowflake metadata operations are free, they're not infinitely scalable and putting unnecessary query volume on a virtual warehouse can create unnecessary strain. Instead of running separate ALTER statements for each column like so:</p><pre><code><code>ALTER TABLE customer_data ALTER COLUMN first_name SET TAG pii_data = 'sensitive';
ALTER TABLE customer_data ALTER COLUMN last_name SET TAG pii_data = 'sensitive';
ALTER TABLE customer_data ALTER COLUMN email SET TAG pii_data = 'sensitive';
ALTER TABLE customer_data ALTER COLUMN phone SET TAG pii_data = 'sensitive';</code></code></pre><p>Batch same-tag operations into a single transaction:</p><pre><code><code>ALTER TABLE customer_data 
  ALTER COLUMN first_name SET TAG pii_data = 'sensitive',
  ALTER COLUMN last_name SET TAG pii_data = 'sensitive',
  ALTER COLUMN email SET TAG pii_data = 'sensitive',
  ALTER COLUMN phone SET TAG pii_data = 'sensitive';</code></code></pre><p>Don't try to set multiple different tag types on the same column in one transaction - race conditions and inconsistent application await.</p><p> If you need to apply both <code>pii_data</code> and <code>data_classification</code> tags to the same column, do it in separate transactions to avoid conflicts.</p><h2>Monitoring and Compliance</h2><p>Snowflake's <a href="https://docs.snowflake.com/en/user-guide/access-history#examples-read-queries">access history</a> becomes your compliance lifeline. Y</p><p>ou need to track what data was accessed, in what format (masked/unmasked), by which user role, at what time, and for how long. </p><p>This isn't just nice-to-have monitoring - it's required for privacy compliance. When regulators ask "who accessed this patient data," you need answers, not shrugs.</p><p>You need real-time visibility into what's masked vs unmasked for each user, policy application success/failure rates, and unusual access patterns that might indicate policy violations. </p><p>This observability layer becomes critical for both security monitoring and compliance reporting.</p><h2>Wrapping Up</h2><p>Implementing ABAC isn't straightforward. If it were, everyone would be doing it already. You're trading the simplicity of "user has role X" for the complexity of "user with attributes A, B, C gets access level Y to data with attributes D, E, F."</p><p>But here's the thing - you're already dealing with that complexity. You're just managing it poorly with an explosion of specific roles and constant manual intervention. ABAC doesn't eliminate complexity; it organizes it in a way that scales.</p><p>Start small with clear use cases, invest in proper tooling and automation upfront, plan for the operational overhead of policy management, and build observability from day one. </p><p>Your future self (and your data governance team) will thank you when the next compliance audit rolls around and you can actually answer questions about who accessed what data, when, and why.</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1ciK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1ciK!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 424w, https://substackcdn.com/image/fetch/$s_!1ciK!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 848w, https://substackcdn.com/image/fetch/$s_!1ciK!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 1272w, https://substackcdn.com/image/fetch/$s_!1ciK!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1ciK!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif" width="444" height="250" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:250,&quot;width&quot;:444,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8050097,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1ciK!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 424w, https://substackcdn.com/image/fetch/$s_!1ciK!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 848w, https://substackcdn.com/image/fetch/$s_!1ciK!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 1272w, https://substackcdn.com/image/fetch/$s_!1ciK!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84dc7fd9-7b73-4cf7-aaa7-df447ce007ea_444x250.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Are we in permission heaven yet?</figcaption></figure></div><p>This concludes this week's deep dive into ABAC implementation. </p><p>Hope you picked up something useful for your own data governance challenges.</p><div><hr></div><p><em>Got ABAC implementation questions or war stories? Hit reply - I read every email and love hearing about real-world data architecture challenges.</em></p><p>Need help implementing ABAC on your enterprise Snowflake + dbt setup? Consider our consulting services at </p><p><a href="https://www.naronadata.com/">https://www.naronadata.com/</a> (formerly Zelytics).</p><h2>Some helpful sources and references</h2><ul><li><p><a href="https://docs.snowflake.com/user-guide/security-column-intro">Snowflake Column-Level Security Documentation</a></p></li><li><p><a href="https://docs.snowflake.com/en/user-guide/tag-based-masking-policies">Snowflake Tag-Based Dynamic Data Masking</a></p></li><li><p><a href="https://docs.snowflake.com/en/user-guide/access-history#examples-read-queries">Snowflake Access History and Query Monitoring</a></p></li><li><p><a href="https://yaml.dev/doc/ruamel.yaml/">ruamel.yaml Documentation</a></p></li><li><p><a href="https://www.blog.zelytics.tech/p/building-custom-dbt-applications">Building Custom dbt Applications</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Data Hustle #1: Finding Value in Optimizing Small Queries]]></title><description><![CDATA[How optimizing small queries in a snowflake+dbt setup can save on a large amount of costs.]]></description><link>https://www.blog.zelytics.tech/p/data-hustle-1-finding-value-in-optimizing</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/data-hustle-1-finding-value-in-optimizing</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Sun, 22 Jun 2025 20:46:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!44dt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Doing more with less is something that every company on the planet benefits from.</p><p>Anyone that has been working with snowflake data warehouses with dbt will at multiple points throughout the lifetime of their warehouses engage into a cost optimisation effort of some sorts.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XqjR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XqjR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!XqjR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!XqjR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!XqjR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XqjR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif" width="480" height="270" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1482640,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XqjR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!XqjR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!XqjR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!XqjR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96800a43-7e1d-4d14-8bdf-8e64f371964e_480x270.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">*Data Engineer after Bosses slack message complaining about the snowflake cost</figcaption></figure></div><p>Data warehouses and associated costs around them are one of the largest non-human costs in a data team and as such are always a prime target for gaining most from a cost cutting effort.</p><p>It can sometimes feel a bit voodoo as to what exactly <em>is</em> the best way to manage costs. It&#8217;s not uncommon to devolve into platitudes or even to just assume that the compute layer will handle everything for you automatically.</p><p>That&#8217;s not to say the snowflake query engine does not do some impressive <strong>heavy</strong> lifting to optimizing cost/performance ratio on many queries but that does NOT mean you don&#8217;t need to put in more effort.</p><p>In this weeks newsletter I&#8217;ll go over some of the fallacies around snowflake cost monitoring and more advanced methods I have been using with my enterprise clients to successfully cut their snowflake spend by 50% on large 6 and 7 figure budgets when they&#8217;ve hit a wall in their cost optimization efforts.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fhb2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fhb2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!fhb2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!fhb2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!fhb2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fhb2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif" width="480" height="270" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3847702,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fhb2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!fhb2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!fhb2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!fhb2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff78c93e7-12c0-4fdf-9e1f-be7bdfb5dcd2_480x270.gif 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">We&#8217;re about to dive into it</figcaption></figure></div><p>This newsletter will assume you know the basics around snowflake costs and basic warehouse management in snowflake. </p><p><strong>&#10060; Fallacy 1: Tracking queries through Role Based Access Control is enough</strong></p><p>There&#8217;s many ways to divide queries into categories in your warehouse. You might split queries based on roles, based on dbt targets or even based on users. While this is a good initial approach, in order to get really detailed insights we will need to add more specific metadata because, as we will learn later, not all statements are created equally.</p><p>When deploying a data stack using snowflake, all sources, whether it be DBT, orchestrators, BI-tools or other applications will connect through some of the supported snowflake connectors.</p><p>Each connector supports the ability to <a href="https://docs.snowflake.com/en/user-guide/cost-attributing">add query tags</a>, this can be a simple:</p><blockquote><p><code>ALTER SESSION SET QUERY_TAG = '&lt;tag_here&gt;'; </code></p></blockquote><p>There are some packages that can help do this for a DBT project, most notably the open source package <a href="https://select.dev/docs/dbt-snowflake-monitoring">dbt-snowflake-monitoring</a> which sets tags for all models and tests and provides very intuitive and comprehensive cost models and monitors for all queries running on the warehouse.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!44dt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!44dt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 424w, https://substackcdn.com/image/fetch/$s_!44dt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 848w, https://substackcdn.com/image/fetch/$s_!44dt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 1272w, https://substackcdn.com/image/fetch/$s_!44dt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!44dt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png" width="1456" height="987" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:987,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:160370,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/166537112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!44dt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 424w, https://substackcdn.com/image/fetch/$s_!44dt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 848w, https://substackcdn.com/image/fetch/$s_!44dt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 1272w, https://substackcdn.com/image/fetch/$s_!44dt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03753d91-d5fb-42c9-82fc-47b508091a6f_1954x1324.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Query tags greatly expand the resolution you get for your cost data tracking efforts</figcaption></figure></div><p><strong>&#10060; Fallacy 2: Performance of all query types scales linearly with larger virtual warehouses / compute</strong></p><p>Consider two types of queries. One is a simple but frequent COPY statement which copies data from an external S3 stage into a snowflake table. Another query is a complex CTE with several complex joins creating a table. These two statements do not have the same performance implications.</p><p>A COPY statement is more strongly influenced by the amount of files and the size of the files we&#8217;re trying to copy over. This means that, with more compute, we might find a similar performance but we get a higher cost. </p><p>For the CTE, we might see that running a <strong>2x more expensive</strong> warehouse <strong>cuts query time by 60%</strong>. If our query runs long enough, this means we safe more money in run time compared to what we are spending on increased compute.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zrYx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zrYx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 424w, https://substackcdn.com/image/fetch/$s_!zrYx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 848w, https://substackcdn.com/image/fetch/$s_!zrYx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 1272w, https://substackcdn.com/image/fetch/$s_!zrYx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zrYx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png" width="1112" height="1244" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1244,&quot;width&quot;:1112,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124898,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/166537112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zrYx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 424w, https://substackcdn.com/image/fetch/$s_!zrYx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 848w, https://substackcdn.com/image/fetch/$s_!zrYx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 1272w, https://substackcdn.com/image/fetch/$s_!zrYx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F481d6b39-0021-4b41-923d-24535170dd7a_1112x1244.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Not all queries scale equally with larger warehouses</figcaption></figure></div><p><strong>&#10060; Fallacy 3: Using a single virtual warehouse to support different kinds of query loads is an efficient configuration.</strong></p><p>As an extension from fallacy 2, many teams will have their use of a virtual warehouse evolve quite substantially over time but this is then not reflected in the composition of virtual warehouses and the queries they carry.</p><p>For data engineering oriented query loads such as COPY statements or INSERTS, DELETES and UPDATES in source tables, it is easy enough to separate these out into their own virtual warehouse.</p><p>For DBT projects, it&#8217;s also possible to set a different <a href="https://docs.getdbt.com/reference/resource-configs/snowflake-configs#configuring-virtual-warehouses">snowflake virtual warehouse</a> in dbt on various levels such as the model level, the materialisation level, a mart level and many more.</p><p>If you have properly tagged queries, it is possible to analyse trends in query usage and set a virtual warehouse of the right size in a DAG oriented approach.</p><p>For example, for many dbt internal tests and commands such as source freshness, these queries might benefit from being run in a smaller warehouse. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vwxs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vwxs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 424w, https://substackcdn.com/image/fetch/$s_!Vwxs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 848w, https://substackcdn.com/image/fetch/$s_!Vwxs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 1272w, https://substackcdn.com/image/fetch/$s_!Vwxs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vwxs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png" width="1456" height="979" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:979,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:188985,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.blog.zelytics.tech/i/166537112?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Vwxs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 424w, https://substackcdn.com/image/fetch/$s_!Vwxs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 848w, https://substackcdn.com/image/fetch/$s_!Vwxs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 1272w, https://substackcdn.com/image/fetch/$s_!Vwxs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F152987ed-33f7-4712-8dc4-207a2b66bcad_1760x1184.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Route queries to the appropriate size warehouse.</figcaption></figure></div><p>Now you might counter: &#8220;but these queries have low run time so does this matter for total cost&#8221;? It does and it brings us to the next fallacy.</p><p><strong>&#10060; Fallacy 4: Short running queries are not important for snowflake costs</strong></p><p>This fallacy actually consists of a few sub-fallacies.</p><p><strong>&#10060; Fallacy 4a: Virtual warehouses can handle any arbitrary amount of concurrency</strong></p><p>While it is true that it&#8217;s possible to scale concurrency through the use of larger warehouses and using multi-cluster warehouses in enterprise accounts, this does not mean a virtual warehouse cannot choke on high query volume.</p><p>The default concurrency is 8 and goes up to 32 queries for a virtual warehouse cluster. </p><p>Now, consider the scenario where we are running thousands upon thousands of queries in a short span of time like what we might have if we&#8217;re running a DBT source freshness command.</p><p>Every transaction has a basic overhead to be executed. Running a high volume of small queries can cause higher than expected query waiting time and cost.</p><p><strong>&#10060; Fallacy 4b: Small queries are handled consistently every time in every warehouse</strong></p><p>I ran an experiment for a simple overwrite for slowly changing data for a set of tables between 1000 records and 50 million records in a snowflake XL warehouse with thousands of queries load and observed a peculiar pattern: The most expensive queries were not from the largest tables nor were they consistently expensive for the same query even though the data in and out remained the same.</p><p>The variation was staggering, the most expensive query of the same kind was in the single $ range and the least expensive was a 1000X cheaper.</p><p>While this may not sound like much, if you are replicating your tables 6 times a day and you have 500 tables where 1 query exceeds $1 you end up with a bill of $3000 a day for this replication.</p><p>Needless to say, moving this to a smaller warehouse resolved the cost of these queries tremendously, as we had less congestion on the older large warehouse and lower cost while running queries at a similar amount of time.</p><div><hr></div><h1>Fin</h1><p>This concludes this weeks newsletter. Hope you picked up something new this week and if you did, show us your support by following the newsletter!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Data Hustle is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Using streams in python for highly resource efficient ingestion in ETL pipelines]]></title><description><![CDATA[how to not waste your memory, disk and cpu one step at a time.]]></description><link>https://www.blog.zelytics.tech/p/using-streams-in-python-for-highly</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/using-streams-in-python-for-highly</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Fri, 05 Jul 2024 16:16:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6c7ddaf5-460d-48a8-b095-f50a6877fd46_800x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever we&#8217;re designing pipelines that are processing data there are tradeoffs and bottlenecks that occur in the process. Say we are loading a large file, if we load that filly wholly in memory we will be constrained by the maximum memory capacity of the computing node that we&#8217;re working with.</p><p>As data engineers, we may be familiar with various ways to remove certain constraints. We may process data in chunks, process data in parallel, process it asynchronously, slap a data orchestrator on it and maybe even go crazy with auto-scaling policies in kubernetes.</p><p>Today, I want to talk about a ELT/ETL pattern that is often overlooked but can be quite powerful and flexible when implented properly. This pattern, is streaming.</p><p>&#8230;.wait but I know what streaming is, isn&#8217;t that about data latency and using fancy frameworks like Kafka to process my data? Yes, that is a form of streaming but not the form this article will dive deeper into.</p><p>In this article, we wil dive deeper into various kind of streaming data types in python and how we can configure them to stream data from various sources to various destinations.</p><h1>What is a &#8220;stream&#8221; and what does it look like?</h1><p>For the purposes of this article, we will maintain the following loose definition of a &#8220;stream&#8221;</p><blockquote><p> &#9997;&#127995; A&nbsp;stream&nbsp;is a sequence&nbsp;of potentially unlimited chunks of data&nbsp;made available over time.</p></blockquote><p>A stream can be thought of as items on a&nbsp;conveyor belt&nbsp;being processed one at a time rather than all at once.</p><p>So essentially, we want to have a data type that can do two things:</p><ol><li><p>Define a sequence of events to process one at a time</p></li><li><p>Allow to read one chunk at a time</p></li></ol><p>Oftentimes you will see this being defined as &#8220;lazy&#8221; computing and it&#8217;s very common across many big data frameworks such as dask and spark. &#8220;Lazy&#8221; here refers to the fact that the chunk of data is only loaded and processed when it is asked to do so rather than precomputing everything up front and then processing each element individually.</p><p>As a data engineer, you&#8217;ve definitely used these sorts of datatypes before.</p><p>Let&#8217;s say you&#8217;ve loaded a CSV file with pandas before with chunking turned on, well, pandas will use a streaming like object in the background to facilitate this!</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234519\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-file-chunking-exaple-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;file-chunking-exaple.py\&quot;>\n        <tr>\n          <td id=\&quot;file-file-chunking-exaple-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-file-chunking-exaple-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>pandas</span> <span class=pl-k>as</span> <span class=pl-s1>pd</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-file-chunking-exaple-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-file-chunking-exaple-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-file-chunking-exaple-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-file-chunking-exaple-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Example of reading a CSV file in chunks with Pandas</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-file-chunking-exaple-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-file-chunking-exaple-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>chunk_size</span> <span class=pl-c1>=</span> <span class=pl-c1>1000</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-file-chunking-exaple-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-file-chunking-exaple-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>chunk</span> <span class=pl-c1>in</span> <span class=pl-s1>pd</span>.<span class=pl-en>read_csv</span>(<span class=pl-s>&amp;#39;large_file.csv&amp;#39;</span>, <span class=pl-s1>chunksize</span><span class=pl-c1>=</span><span class=pl-s1>chunk_size</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-file-chunking-exaple-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-file-chunking-exaple-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>process</span>(<span class=pl-s1>chunk</span>)  <span class=pl-c># Replace with your processing logic</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/7e06961c3b248eeaa68a3a5e4e79fca0/raw/f1b625a729e75dfd25e689f5a3ff6714abc042a2/file-chunking-exaple.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/7e06961c3b248eeaa68a3a5e4e79fca0#file-file-chunking-exaple-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          file-chunking-exaple.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234519" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-file-chunking-exaple-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="file-chunking-exaple.py">
        <tbody><tr>
          <td id="file-file-chunking-exaple-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-file-chunking-exaple-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">pandas</span> <span class="pl-k">as</span> <span class="pl-s1">pd</span></td>
        </tr>
        <tr>
          <td id="file-file-chunking-exaple-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-file-chunking-exaple-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-file-chunking-exaple-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-file-chunking-exaple-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Example of reading a CSV file in chunks with Pandas</span></td>
        </tr>
        <tr>
          <td id="file-file-chunking-exaple-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-file-chunking-exaple-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">chunk_size</span> <span class="pl-c1">=</span> <span class="pl-c1">1000</span></td>
        </tr>
        <tr>
          <td id="file-file-chunking-exaple-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-file-chunking-exaple-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">chunk</span> <span class="pl-c1">in</span> <span class="pl-s1">pd</span>.<span class="pl-en">read_csv</span>(<span class="pl-s">'large_file.csv'</span>, <span class="pl-s1">chunksize</span><span class="pl-c1">=</span><span class="pl-s1">chunk_size</span>):</td>
        </tr>
        <tr>
          <td id="file-file-chunking-exaple-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-file-chunking-exaple-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">process</span>(<span class="pl-s1">chunk</span>)  <span class="pl-c"># Replace with your processing logic</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/7e06961c3b248eeaa68a3a5e4e79fca0/raw/f1b625a729e75dfd25e689f5a3ff6714abc042a2/file-chunking-exaple.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/7e06961c3b248eeaa68a3a5e4e79fca0#file-file-chunking-exaple-py" class="Link--inTextBlock">
          file-chunking-exaple.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>well&#8230;to be fair, if we are talking stritcly canonical python, you may be aware that we are specifically talking about <code>iterators</code> .</p><p>Now you may say: &#8220;Hey but I already know those, i&#8217;m outa here&#8221;.</p><p>Yes, you may be aware of iterators but there&#8217;s a suprising amount of ways that you can leverage them to stream data from and to sources in ways you may not expect.</p><p>If you don&#8217;t know what <code>iterators</code> are, the following section is for you.</p><h1>A way to iterate and iterate and iterate</h1><p>Feel free to skip this section if you are familiar enough with <code>iterators</code> .</p><p>An <code>iterable</code> is any Python object capable of returning its elements one at a time, allowing it to be iterated over in a loop. Examples include lists, tuples, sets, dictionaries, and strings. An object is considered iterable if it implements the <code>__iter__()</code> method, which returns an iterator.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234530\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-item-list-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;item-list.py\&quot;>\n        <tr>\n          <td id=\&quot;file-item-list-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-item-list-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>my_list</span> <span class=pl-c1>=</span> [<span class=pl-c1>1</span>, <span class=pl-c1>2</span>, <span class=pl-c1>3</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-item-list-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-item-list-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>item</span> <span class=pl-c1>in</span> <span class=pl-s1>my_list</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-item-list-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-item-list-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>item</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/32901a19d85c2b146e9f0a7a1001a84a/raw/6d1d78c3446f216affea8bd2222fd3362efd2bd3/item-list.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/32901a19d85c2b146e9f0a7a1001a84a#file-item-list-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          item-list.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234530" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-item-list-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="item-list.py">
        <tbody><tr>
          <td id="file-item-list-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-item-list-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">my_list</span> <span class="pl-c1">=</span> [<span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>]</td>
        </tr>
        <tr>
          <td id="file-item-list-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-item-list-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">item</span> <span class="pl-c1">in</span> <span class="pl-s1">my_list</span>:</td>
        </tr>
        <tr>
          <td id="file-item-list-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-item-list-py-LC3" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">item</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/32901a19d85c2b146e9f0a7a1001a84a/raw/6d1d78c3446f216affea8bd2222fd3362efd2bd3/item-list.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/32901a19d85c2b146e9f0a7a1001a84a#file-item-list-py" class="Link--inTextBlock">
          item-list.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>An <code>iterator</code> is an object that represents a stream of data. It returns data one element at a time when the <code>__next__()</code> method is called. Iterators keep track of their current position. An iterator is created by calling the <code>__iter__()</code> method on an iterable, which returns the iterator object itself.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234540\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-iterator-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;iterator.py\&quot;>\n        <tr>\n          <td id=\&quot;file-iterator-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>my_list</span> <span class=pl-c1>=</span> [<span class=pl-c1>1</span>, <span class=pl-c1>2</span>, <span class=pl-c1>3</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>iterator</span> <span class=pl-c1>=</span> <span class=pl-en>iter</span>(<span class=pl-s1>my_list</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>next</span>(<span class=pl-s1>iterator</span>))  <span class=pl-c># Output: 1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>next</span>(<span class=pl-s1>iterator</span>))  <span class=pl-c># Output: 2</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>next</span>(<span class=pl-s1>iterator</span>))  <span class=pl-c># Output: 3</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Calling next again will raise a StopIteration Exception</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/09a98ec19cb5dc5dea49c8e7fb496cba/raw/2b538a68e0eaa2e801d2f9c722a879d8b652b6ee/iterator.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/09a98ec19cb5dc5dea49c8e7fb496cba#file-iterator-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          iterator.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234540" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-iterator-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="iterator.py">
        <tbody><tr>
          <td id="file-iterator-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-iterator-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">my_list</span> <span class="pl-c1">=</span> [<span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>]</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-iterator-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">iterator</span> <span class="pl-c1">=</span> <span class="pl-en">iter</span>(<span class="pl-s1">my_list</span>)</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-iterator-py-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-iterator-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">next</span>(<span class="pl-s1">iterator</span>))  <span class="pl-c"># Output: 1</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-iterator-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">next</span>(<span class="pl-s1">iterator</span>))  <span class="pl-c"># Output: 2</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-iterator-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">next</span>(<span class="pl-s1">iterator</span>))  <span class="pl-c"># Output: 3</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-iterator-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Calling next again will raise a StopIteration Exception</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/09a98ec19cb5dc5dea49c8e7fb496cba/raw/2b538a68e0eaa2e801d2f9c722a879d8b652b6ee/iterator.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/09a98ec19cb5dc5dea49c8e7fb496cba#file-iterator-py" class="Link--inTextBlock">
          iterator.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>The Abstract Base Class (ABC) <code>iterator</code> protocol defines two methods that an object must implement to be considered an iterator:</p><ul><li><p><code>__iter__()</code> returns the iterator object itself.</p></li><li><p><code>__next__()</code> returns the next item in the sequence. If there are no more items, it raises <code>StopIteration</code>.</p></li></ul><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234546\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-iterator-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;iterator.py\&quot;>\n        <tr>\n          <td id=\&quot;file-iterator-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>MyIterator</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__init__</span>(<span class=pl-s1>self</span>, <span class=pl-s1>data</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>data</span> <span class=pl-c1>=</span> <span class=pl-s1>data</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>index</span> <span class=pl-c1>=</span> <span class=pl-c1>0</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__iter__</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s1>self</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__next__</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>if</span> <span class=pl-s1>self</span>.<span class=pl-s1>index</span> <span class=pl-c1>&amp;lt;</span> <span class=pl-en>len</span>(<span class=pl-s1>self</span>.<span class=pl-s1>data</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>item</span> <span class=pl-c1>=</span> <span class=pl-s1>self</span>.<span class=pl-s1>data</span>[<span class=pl-s1>self</span>.<span class=pl-s1>index</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>self</span>.<span class=pl-s1>index</span> <span class=pl-c1>+=</span> <span class=pl-c1>1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>return</span> <span class=pl-s1>item</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>else</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>raise</span> <span class=pl-v>StopIteration</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>my_iter</span> <span class=pl-c1>=</span> <span class=pl-v>MyIterator</span>([<span class=pl-c1>1</span>, <span class=pl-c1>2</span>, <span class=pl-c1>3</span>])</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>item</span> <span class=pl-c1>in</span> <span class=pl-s1>my_iter</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-iterator-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-iterator-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>item</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/8271a994b4c0363435e59a29109f2187/raw/cfbef1d1e8e28e336fe995fb8b564a27b2555269/iterator.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/8271a994b4c0363435e59a29109f2187#file-iterator-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          iterator.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234546" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-iterator-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="iterator.py">
        <tbody><tr>
          <td id="file-iterator-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-iterator-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">MyIterator</span>:</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-iterator-py-LC2" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">data</span>):</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-iterator-py-LC3" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">data</span> <span class="pl-c1">=</span> <span class="pl-s1">data</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-iterator-py-LC4" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">index</span> <span class="pl-c1">=</span> <span class="pl-c1">0</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-iterator-py-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-iterator-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__iter__</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-iterator-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s1">self</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-iterator-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-iterator-py-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__next__</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-iterator-py-LC10" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">if</span> <span class="pl-s1">self</span>.<span class="pl-s1">index</span> <span class="pl-c1">&lt;</span> <span class="pl-en">len</span>(<span class="pl-s1">self</span>.<span class="pl-s1">data</span>):</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-iterator-py-LC11" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">item</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-s1">data</span>[<span class="pl-s1">self</span>.<span class="pl-s1">index</span>]</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-iterator-py-LC12" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">self</span>.<span class="pl-s1">index</span> <span class="pl-c1">+=</span> <span class="pl-c1">1</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-iterator-py-LC13" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">return</span> <span class="pl-s1">item</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-iterator-py-LC14" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">else</span>:</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-iterator-py-LC15" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">raise</span> <span class="pl-v">StopIteration</span></td>
        </tr>
        <tr>
          <td id="file-iterator-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-iterator-py-LC16" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-iterator-py-LC17" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">my_iter</span> <span class="pl-c1">=</span> <span class="pl-v">MyIterator</span>([<span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>])</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-iterator-py-LC18" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">item</span> <span class="pl-c1">in</span> <span class="pl-s1">my_iter</span>:</td>
        </tr>
        <tr>
          <td id="file-iterator-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-iterator-py-LC19" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">item</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/8271a994b4c0363435e59a29109f2187/raw/cfbef1d1e8e28e336fe995fb8b564a27b2555269/iterator.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/8271a994b4c0363435e59a29109f2187#file-iterator-py" class="Link--inTextBlock">
          iterator.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>A generator is a special type of iterator created using a function that uses the <code>yield</code> statement to return data one item at a time. Generators provide a convenient way to implement iterators without needing to write a full class with <code>__iter__()</code> and <code>__next__()</code> methods.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234554\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-generator\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-text  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;\&quot; data-tagsearch-path=\&quot;generator\&quot;>\n        <tr>\n          <td id=\&quot;file-generator-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-generator-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>def my_generator():</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-generator-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    yield 1</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-generator-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    yield 2</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-generator-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    yield 3</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-generator-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-generator-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>gen = my_generator()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-generator-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>for item in gen:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-generator-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-generator-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    print(item)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/f34b73ffb25810074e114cfbff7d162a/raw/44fa0ac21588b3c6cd43eb196b5e90580b5f4191/generator\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/f34b73ffb25810074e114cfbff7d162a#file-generator\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          generator\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234554" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-generator" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-text  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="" data-tagsearch-path="generator">
        <tbody><tr>
          <td id="file-generator-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-generator-LC1" class="blob-code blob-code-inner js-file-line">def my_generator():</td>
        </tr>
        <tr>
          <td id="file-generator-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-generator-LC2" class="blob-code blob-code-inner js-file-line">    yield 1</td>
        </tr>
        <tr>
          <td id="file-generator-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-generator-LC3" class="blob-code blob-code-inner js-file-line">    yield 2</td>
        </tr>
        <tr>
          <td id="file-generator-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-generator-LC4" class="blob-code blob-code-inner js-file-line">    yield 3</td>
        </tr>
        <tr>
          <td id="file-generator-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-generator-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-generator-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-generator-LC6" class="blob-code blob-code-inner js-file-line">gen = my_generator()</td>
        </tr>
        <tr>
          <td id="file-generator-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-generator-LC7" class="blob-code blob-code-inner js-file-line">for item in gen:</td>
        </tr>
        <tr>
          <td id="file-generator-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-generator-LC8" class="blob-code blob-code-inner js-file-line">    print(item)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/f34b73ffb25810074e114cfbff7d162a/raw/44fa0ac21588b3c6cd43eb196b5e90580b5f4191/generator" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/f34b73ffb25810074e114cfbff7d162a#file-generator" class="Link--inTextBlock">
          generator
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>A for loop in Python can be used to iterate over an iterable object, executing the loop body for each item.</p><p>The <code>yield</code> statement is used in a generator function to return data without terminating the function. The function state is saved, allowing the generator to resume where it left off when <code>next()</code> is called again.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234572\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-yield-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;yield.py\&quot;>\n        <tr>\n          <td id=\&quot;file-yield-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-yield-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>count_up_to</span>(<span class=pl-s1>max</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-yield-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>count</span> <span class=pl-c1>=</span> <span class=pl-c1>1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-yield-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>while</span> <span class=pl-s1>count</span> <span class=pl-c1>&amp;lt;=</span> <span class=pl-s1>max</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-yield-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>yield</span> <span class=pl-s1>count</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-yield-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>count</span> <span class=pl-c1>+=</span> <span class=pl-c1>1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-yield-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-yield-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>counter</span> <span class=pl-c1>=</span> <span class=pl-en>count_up_to</span>(<span class=pl-c1>3</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-yield-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>next</span>(<span class=pl-s1>counter</span>))  <span class=pl-c># Output: 1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-yield-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>next</span>(<span class=pl-s1>counter</span>))  <span class=pl-c># Output: 2</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-yield-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>next</span>(<span class=pl-s1>counter</span>))  <span class=pl-c># Output: 3</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-yield-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-yield-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Calling next again will raise StopIteration</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/c9c3d045f1663fbcb548b6d79e7921d3/raw/997dc4c2f40a8940b507e6e8b8f8477bfbc1d165/yield.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/c9c3d045f1663fbcb548b6d79e7921d3#file-yield-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          yield.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234572" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-yield-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="yield.py">
        <tbody><tr>
          <td id="file-yield-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-yield-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">count_up_to</span>(<span class="pl-s1">max</span>):</td>
        </tr>
        <tr>
          <td id="file-yield-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-yield-py-LC2" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">count</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span></td>
        </tr>
        <tr>
          <td id="file-yield-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-yield-py-LC3" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">while</span> <span class="pl-s1">count</span> <span class="pl-c1">&lt;=</span> <span class="pl-s1">max</span>:</td>
        </tr>
        <tr>
          <td id="file-yield-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-yield-py-LC4" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">yield</span> <span class="pl-s1">count</span></td>
        </tr>
        <tr>
          <td id="file-yield-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-yield-py-LC5" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">count</span> <span class="pl-c1">+=</span> <span class="pl-c1">1</span></td>
        </tr>
        <tr>
          <td id="file-yield-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-yield-py-LC6" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-yield-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-yield-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">counter</span> <span class="pl-c1">=</span> <span class="pl-en">count_up_to</span>(<span class="pl-c1">3</span>)</td>
        </tr>
        <tr>
          <td id="file-yield-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-yield-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">next</span>(<span class="pl-s1">counter</span>))  <span class="pl-c"># Output: 1</span></td>
        </tr>
        <tr>
          <td id="file-yield-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-yield-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">next</span>(<span class="pl-s1">counter</span>))  <span class="pl-c"># Output: 2</span></td>
        </tr>
        <tr>
          <td id="file-yield-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-yield-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">next</span>(<span class="pl-s1">counter</span>))  <span class="pl-c"># Output: 3</span></td>
        </tr>
        <tr>
          <td id="file-yield-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-yield-py-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Calling next again will raise StopIteration</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/c9c3d045f1663fbcb548b6d79e7921d3/raw/997dc4c2f40a8940b507e6e8b8f8477bfbc1d165/yield.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/c9c3d045f1663fbcb548b6d79e7921d3#file-yield-py" class="Link--inTextBlock">
          yield.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>By understanding these components, you can effectively use and create iterators and generators in Python to handle sequences of data efficiently.</p><h1>Using iterators for streaming data from various sources</h1><p>In this section we will go over a few examples of common sources you may want to load from and to as a data engineer.</p><h2>Streaming data from an API with HTTPX.stream</h2><p>To stream data from an API, you can use the <code>httpx</code> library. This is particularly useful for downloading large files or handling continuous data feeds.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234578\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-httpx-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;httpx.py\&quot;>\n        <tr>\n          <td id=\&quot;file-httpx-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>httpx</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>stream_data_from_api</span>(<span class=pl-s1>url</span>, <span class=pl-s1>chunk_size</span><span class=pl-c1>=</span><span class=pl-c1>1024</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>with</span> <span class=pl-s1>httpx</span>.<span class=pl-en>stream</span>(<span class=pl-s>&amp;#39;GET&amp;#39;</span>, <span class=pl-s1>url</span>) <span class=pl-k>as</span> <span class=pl-s1>response</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>for</span> <span class=pl-s1>chunk</span> <span class=pl-c1>in</span> <span class=pl-s1>response</span>.<span class=pl-en>iter_bytes</span>(<span class=pl-s1>chunk_size</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>yield</span> <span class=pl-s1>chunk</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Example usage</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>url</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;&amp;lt;https://example.com/large_file.zip&amp;gt;&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>chunk</span> <span class=pl-c1>in</span> <span class=pl-en>stream_data_from_api</span>(<span class=pl-s1>url</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Process each chunk</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-httpx-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-httpx-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>chunk</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/097686e8b076dc58b5fb486b87648cf0/raw/4988483db40bf118b76d8e8f7fb0cd5391adfc56/httpx.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/097686e8b076dc58b5fb486b87648cf0#file-httpx-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          httpx.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234578" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-httpx-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="httpx.py">
        <tbody><tr>
          <td id="file-httpx-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-httpx-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">httpx</span></td>
        </tr>
        <tr>
          <td id="file-httpx-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-httpx-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-httpx-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-httpx-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">stream_data_from_api</span>(<span class="pl-s1">url</span>, <span class="pl-s1">chunk_size</span><span class="pl-c1">=</span><span class="pl-c1">1024</span>):</td>
        </tr>
        <tr>
          <td id="file-httpx-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-httpx-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">with</span> <span class="pl-s1">httpx</span>.<span class="pl-en">stream</span>(<span class="pl-s">'GET'</span>, <span class="pl-s1">url</span>) <span class="pl-k">as</span> <span class="pl-s1">response</span>:</td>
        </tr>
        <tr>
          <td id="file-httpx-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-httpx-py-LC5" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">for</span> <span class="pl-s1">chunk</span> <span class="pl-c1">in</span> <span class="pl-s1">response</span>.<span class="pl-en">iter_bytes</span>(<span class="pl-s1">chunk_size</span>):</td>
        </tr>
        <tr>
          <td id="file-httpx-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-httpx-py-LC6" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">yield</span> <span class="pl-s1">chunk</span></td>
        </tr>
        <tr>
          <td id="file-httpx-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-httpx-py-LC7" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-httpx-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-httpx-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Example usage</span></td>
        </tr>
        <tr>
          <td id="file-httpx-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-httpx-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">url</span> <span class="pl-c1">=</span> <span class="pl-s">'&lt;https://example.com/large_file.zip&gt;'</span></td>
        </tr>
        <tr>
          <td id="file-httpx-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-httpx-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">chunk</span> <span class="pl-c1">in</span> <span class="pl-en">stream_data_from_api</span>(<span class="pl-s1">url</span>):</td>
        </tr>
        <tr>
          <td id="file-httpx-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-httpx-py-LC11" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Process each chunk</span></td>
        </tr>
        <tr>
          <td id="file-httpx-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-httpx-py-LC12" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">chunk</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/097686e8b076dc58b5fb486b87648cf0/raw/4988483db40bf118b76d8e8f7fb0cd5391adfc56/httpx.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/097686e8b076dc58b5fb486b87648cf0#file-httpx-py" class="Link--inTextBlock">
          httpx.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h2>Streaming Data to and from S3 with S3FS</h2><p>For handling data in Amazon S3, the <code>s3fs</code> library allows you to stream data directly from S3 buckets without downloading the entire file.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234591\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-s3fs-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;s3fs.py\&quot;>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>s3fs</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>stream_data_from_s3</span>(<span class=pl-s1>bucket_name</span>, <span class=pl-s1>file_path</span>, <span class=pl-s1>chunk_size</span><span class=pl-c1>=</span><span class=pl-c1>1024</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>fs</span> <span class=pl-c1>=</span> <span class=pl-s1>s3fs</span>.<span class=pl-v>S3FileSystem</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>with</span> <span class=pl-s1>fs</span>.<span class=pl-en>open</span>(<span class=pl-s>f&amp;#39;<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>bucket_name</span><span class=pl-kos>}</span></span>/<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>file_path</span><span class=pl-kos>}</span></span>&amp;#39;</span>, <span class=pl-s>&amp;#39;rb&amp;#39;</span>) <span class=pl-k>as</span> <span class=pl-s1>file</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>while</span> <span class=pl-s1>chunk</span> <span class=pl-c1>:=</span> <span class=pl-s1>file</span>.<span class=pl-en>read</span>(<span class=pl-s1>chunk_size</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>yield</span> <span class=pl-s1>chunk</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Example usage</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>bucket_name</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;my-bucket&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>file_path</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;large_file.csv&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>chunk</span> <span class=pl-c1>in</span> <span class=pl-en>stream_data_from_s3</span>(<span class=pl-s1>bucket_name</span>, <span class=pl-s1>file_path</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Process each chunk</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-s3fs-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-s3fs-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>chunk</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/b4919e1e937c7cb38e192173efd85bd3/raw/0efdcd9eaf18eb5d46f8c7c0b1e191cf4579c79a/s3fs.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/b4919e1e937c7cb38e192173efd85bd3#file-s3fs-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          s3fs.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234591" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-s3fs-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="s3fs.py">
        <tbody><tr>
          <td id="file-s3fs-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-s3fs-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">s3fs</span></td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-s3fs-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-s3fs-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">stream_data_from_s3</span>(<span class="pl-s1">bucket_name</span>, <span class="pl-s1">file_path</span>, <span class="pl-s1">chunk_size</span><span class="pl-c1">=</span><span class="pl-c1">1024</span>):</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-s3fs-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">fs</span> <span class="pl-c1">=</span> <span class="pl-s1">s3fs</span>.<span class="pl-v">S3FileSystem</span>()</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-s3fs-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">with</span> <span class="pl-s1">fs</span>.<span class="pl-en">open</span>(<span class="pl-s">f'<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">bucket_name</span><span class="pl-kos">}</span></span>/<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">file_path</span><span class="pl-kos">}</span></span>'</span>, <span class="pl-s">'rb'</span>) <span class="pl-k">as</span> <span class="pl-s1">file</span>:</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-s3fs-py-LC6" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">while</span> <span class="pl-s1">chunk</span> <span class="pl-c1">:=</span> <span class="pl-s1">file</span>.<span class="pl-en">read</span>(<span class="pl-s1">chunk_size</span>):</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-s3fs-py-LC7" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">yield</span> <span class="pl-s1">chunk</span></td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-s3fs-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-s3fs-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Example usage</span></td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-s3fs-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">bucket_name</span> <span class="pl-c1">=</span> <span class="pl-s">'my-bucket'</span></td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-s3fs-py-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">file_path</span> <span class="pl-c1">=</span> <span class="pl-s">'large_file.csv'</span></td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-s3fs-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">chunk</span> <span class="pl-c1">in</span> <span class="pl-en">stream_data_from_s3</span>(<span class="pl-s1">bucket_name</span>, <span class="pl-s1">file_path</span>):</td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-s3fs-py-LC13" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Process each chunk</span></td>
        </tr>
        <tr>
          <td id="file-s3fs-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-s3fs-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">chunk</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/b4919e1e937c7cb38e192173efd85bd3/raw/0efdcd9eaf18eb5d46f8c7c0b1e191cf4579c79a/s3fs.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/b4919e1e937c7cb38e192173efd85bd3#file-s3fs-py" class="Link--inTextBlock">
          s3fs.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h2>Streaming Data to a Data Warehouse with Snowflake Connector</h2><p>When streaming data to a data warehouse like Snowflake, I have a separate article going in depth in to <a href="https://tonyzeljkovic.substack.com/p/a-deep-dive-into-the-snowflake-python">how to use the snowflake connector</a> to do so. Here I will illustrate a few ways in which we can stream data with the snowflake connector.</p><p>When retrieving data, we can retrieve an iterator of pandas dataframes for examples. With each iteration, the connector will download the next chunk of results data:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234602\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-fetch_pandas_batches-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;fetch_pandas_batches.py\&quot;>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>cursor</span> <span class=pl-c1>=</span> <span class=pl-s1>connection</span>.<span class=pl-en>cursor</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>results</span> <span class=pl-c1>=</span> <span class=pl-s1>cursor</span>.<span class=pl-en>fetch_pandas_batches</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>assert</span> <span class=pl-en>isinstance</span>(<span class=pl-s1>results</span>, <span class=pl-v>Generator</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>result</span> <span class=pl-c1>in</span> <span class=pl-s1>results</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>assert</span> <span class=pl-en>isinstance</span>(<span class=pl-s1>result</span>, <span class=pl-v>PandasDataFrame</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-fetch_pandas_batches-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-fetch_pandas_batches-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>break</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/56acaffaf79691be050fd4f254f157dc/raw/504476d467c192197fee49497667c705cf28ef38/fetch_pandas_batches.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/56acaffaf79691be050fd4f254f157dc#file-fetch_pandas_batches-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          fetch_pandas_batches.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234602" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-fetch_pandas_batches-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="fetch_pandas_batches.py">
        <tbody><tr>
          <td id="file-fetch_pandas_batches-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-fetch_pandas_batches-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">cursor</span> <span class="pl-c1">=</span> <span class="pl-s1">connection</span>.<span class="pl-en">cursor</span>()</td>
        </tr>
        <tr>
          <td id="file-fetch_pandas_batches-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-fetch_pandas_batches-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">results</span> <span class="pl-c1">=</span> <span class="pl-s1">cursor</span>.<span class="pl-en">fetch_pandas_batches</span>()</td>
        </tr>
        <tr>
          <td id="file-fetch_pandas_batches-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-fetch_pandas_batches-py-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-fetch_pandas_batches-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-fetch_pandas_batches-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-k">assert</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">results</span>, <span class="pl-v">Generator</span>)</td>
        </tr>
        <tr>
          <td id="file-fetch_pandas_batches-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-fetch_pandas_batches-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">result</span> <span class="pl-c1">in</span> <span class="pl-s1">results</span>:</td>
        </tr>
        <tr>
          <td id="file-fetch_pandas_batches-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-fetch_pandas_batches-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">assert</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">result</span>, <span class="pl-v">PandasDataFrame</span>)</td>
        </tr>
        <tr>
          <td id="file-fetch_pandas_batches-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-fetch_pandas_batches-py-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">break</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/56acaffaf79691be050fd4f254f157dc/raw/504476d467c192197fee49497667c705cf28ef38/fetch_pandas_batches.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/56acaffaf79691be050fd4f254f157dc#file-fetch_pandas_batches-py" class="Link--inTextBlock">
          fetch_pandas_batches.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>It&#8217;s also possible to stream data TO snowflake by supplying it with a file stream object like so:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234617\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-snowio-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;snowio.py\&quot;>\n        <tr>\n          <td id=\&quot;file-snowio-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>with</span> <span class=pl-s1>connection</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-k>if</span> <span class=pl-s1>file_path</span> <span class=pl-c1>is</span> <span class=pl-c1>not</span> <span class=pl-c1>None</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s1>counter</span> <span class=pl-c1>=</span> <span class=pl-c1>0</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s1>cursor_execution_config</span>.<span class=pl-s1>command</span> <span class=pl-c1>=</span> <span class=pl-s>f&amp;quot;PUT file://<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>snowflake_file_name</span><span class=pl-kos>}</span></span>_<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>counter</span><span class=pl-kos>}</span></span> @<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>full_qualified_stage_name</span><span class=pl-kos>}</span></span> OVERWRITE = <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>overwrite</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-k>with</span> <span class=pl-en>open</span>(<span class=pl-s1>file_path</span>, <span class=pl-s>&amp;quot;rb&amp;quot;</span>) <span class=pl-k>as</span> <span class=pl-s1>f</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-k>if</span> <span class=pl-s1>chunk_size</span> <span class=pl-c1>==</span> <span class=pl-c1>0</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-k>raise</span> <span class=pl-v>ValueError</span>(</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s>&amp;quot;Chunk size of 0 is not allowed for filestream pushing.&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              )</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-k>elif</span> <span class=pl-s1>chunk_size</span> <span class=pl-c1>&amp;gt;</span> <span class=pl-c1>0</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s1>lines</span> <span class=pl-c1>=</span> []</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-k>for</span> (</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s1>line</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              ) <span class=pl-c1>in</span> (</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s1>f</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              ):  <span class=pl-c># NOTE: This only works for file types that are splittable line by line like CSVs.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s1>lines</span>.<span class=pl-en>append</span>(<span class=pl-s1>line</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-k>if</span> <span class=pl-en>len</span>(<span class=pl-s1>lines</span>) <span class=pl-c1>&amp;gt;=</span> <span class=pl-s1>chunk_size</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      <span class=pl-s1>counter</span> <span class=pl-c1>+=</span> <span class=pl-c1>1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      <span class=pl-s1>filestream</span> <span class=pl-c1>=</span> <span class=pl-s1>io</span>.<span class=pl-v>BytesIO</span>(<span class=pl-s>b&amp;quot;&amp;quot;</span>.<span class=pl-en>join</span>(<span class=pl-s1>lines</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      <span class=pl-s1>cursor</span> <span class=pl-c1>=</span> <span class=pl-s1>cursor</span>.<span class=pl-en>execute</span>(</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                          <span class=pl-c1>*</span><span class=pl-s1>cursor_execution_config</span>.<span class=pl-en>dict</span>(),</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                          <span class=pl-s1>file_stream</span><span class=pl-c1>=</span><span class=pl-s1>filestream</span>,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      )</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      <span class=pl-s1>lines</span> <span class=pl-c1>=</span> []</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-k>if</span> <span class=pl-s1>lines</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s1>counter</span> <span class=pl-c1>+=</span> <span class=pl-c1>1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s1>filestream</span> <span class=pl-c1>=</span> <span class=pl-s1>io</span>.<span class=pl-v>BytesIO</span>(<span class=pl-s>b&amp;quot;&amp;quot;</span>.<span class=pl-en>join</span>(<span class=pl-s1>lines</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-s1>cursor</span> <span class=pl-c1>=</span> <span class=pl-s1>cursor</span>.<span class=pl-en>execute</span>(</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      <span class=pl-c1>**</span><span class=pl-s1>cursor_execution_config</span>.<span class=pl-en>dict</span>(),</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                      <span class=pl-s1>file_stream</span><span class=pl-c1>=</span><span class=pl-s1>filestream</span>,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  )</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                  <span class=pl-en>debug</span>(<span class=pl-s>f&amp;quot;Final chunk of <span class=pl-s1><span class=pl-kos>{</span><span class=pl-en>len</span>(<span class=pl-s1>lines</span>)<span class=pl-kos>}</span></span> lines pushed.&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-k>else</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s1>cursor</span> <span class=pl-c1>=</span> <span class=pl-s1>cursor</span>.<span class=pl-en>execute</span>(<span class=pl-c1>**</span><span class=pl-s1>cursor_execution_config</span>.<span class=pl-en>dict</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-k>if</span> <span class=pl-en>isinstance</span>(<span class=pl-s1>cursor</span>, <span class=pl-v>SnowflakeCursor</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-c># SnowflakeExecuteEvent(vars(self.cursor)).log()</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s1>logger</span>.<span class=pl-en>info</span>(<span class=pl-s>f&amp;quot;cursor is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>cursor</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-k>else</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s1>logger</span>.<span class=pl-en>info</span>(<span class=pl-s>f&amp;quot;SQL execution results is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>cursor</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-snowio-py-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-snowio-py-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-k>return</span> <span class=pl-s1>self</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/f52be97f86ebba112f9539c7e1eeb0f2/raw/4975ba5d0489fe75011965ea917695cf02015a61/snowio.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/f52be97f86ebba112f9539c7e1eeb0f2#file-snowio-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          snowio.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234617" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-snowio-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="snowio.py">
        <tbody><tr>
          <td id="file-snowio-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-snowio-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">with</span> <span class="pl-s1">connection</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-snowio-py-LC2" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">if</span> <span class="pl-s1">file_path</span> <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-c1">None</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-snowio-py-LC3" class="blob-code blob-code-inner js-file-line">      <span class="pl-s1">counter</span> <span class="pl-c1">=</span> <span class="pl-c1">0</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-snowio-py-LC4" class="blob-code blob-code-inner js-file-line">      <span class="pl-s1">cursor_execution_config</span>.<span class="pl-s1">command</span> <span class="pl-c1">=</span> <span class="pl-s">f"PUT file://<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">snowflake_file_name</span><span class="pl-kos">}</span></span>_<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">counter</span><span class="pl-kos">}</span></span> @<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">full_qualified_stage_name</span><span class="pl-kos">}</span></span> OVERWRITE = <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">overwrite</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-snowio-py-LC5" class="blob-code blob-code-inner js-file-line">      <span class="pl-k">with</span> <span class="pl-en">open</span>(<span class="pl-s1">file_path</span>, <span class="pl-s">"rb"</span>) <span class="pl-k">as</span> <span class="pl-s1">f</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-snowio-py-LC6" class="blob-code blob-code-inner js-file-line">          <span class="pl-k">if</span> <span class="pl-s1">chunk_size</span> <span class="pl-c1">==</span> <span class="pl-c1">0</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-snowio-py-LC7" class="blob-code blob-code-inner js-file-line">              <span class="pl-k">raise</span> <span class="pl-v">ValueError</span>(</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-snowio-py-LC8" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s">"Chunk size of 0 is not allowed for filestream pushing."</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-snowio-py-LC9" class="blob-code blob-code-inner js-file-line">              )</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-snowio-py-LC10" class="blob-code blob-code-inner js-file-line">          <span class="pl-k">elif</span> <span class="pl-s1">chunk_size</span> <span class="pl-c1">&gt;</span> <span class="pl-c1">0</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-snowio-py-LC11" class="blob-code blob-code-inner js-file-line">              <span class="pl-s1">lines</span> <span class="pl-c1">=</span> []</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-snowio-py-LC12" class="blob-code blob-code-inner js-file-line">              <span class="pl-k">for</span> (</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-snowio-py-LC13" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s1">line</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-snowio-py-LC14" class="blob-code blob-code-inner js-file-line">              ) <span class="pl-c1">in</span> (</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-snowio-py-LC15" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s1">f</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-snowio-py-LC16" class="blob-code blob-code-inner js-file-line">              ):  <span class="pl-c"># NOTE: This only works for file types that are splittable line by line like CSVs.</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-snowio-py-LC17" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s1">lines</span>.<span class="pl-en">append</span>(<span class="pl-s1">line</span>)</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-snowio-py-LC18" class="blob-code blob-code-inner js-file-line">                  <span class="pl-k">if</span> <span class="pl-en">len</span>(<span class="pl-s1">lines</span>) <span class="pl-c1">&gt;=</span> <span class="pl-s1">chunk_size</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-snowio-py-LC19" class="blob-code blob-code-inner js-file-line">                      <span class="pl-s1">counter</span> <span class="pl-c1">+=</span> <span class="pl-c1">1</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-snowio-py-LC20" class="blob-code blob-code-inner js-file-line">                      <span class="pl-s1">filestream</span> <span class="pl-c1">=</span> <span class="pl-s1">io</span>.<span class="pl-v">BytesIO</span>(<span class="pl-s">b""</span>.<span class="pl-en">join</span>(<span class="pl-s1">lines</span>))</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-snowio-py-LC21" class="blob-code blob-code-inner js-file-line">                      <span class="pl-s1">cursor</span> <span class="pl-c1">=</span> <span class="pl-s1">cursor</span>.<span class="pl-en">execute</span>(</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-snowio-py-LC22" class="blob-code blob-code-inner js-file-line">                          <span class="pl-c1">*</span><span class="pl-s1">cursor_execution_config</span>.<span class="pl-en">dict</span>(),</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-snowio-py-LC23" class="blob-code blob-code-inner js-file-line">                          <span class="pl-s1">file_stream</span><span class="pl-c1">=</span><span class="pl-s1">filestream</span>,</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-snowio-py-LC24" class="blob-code blob-code-inner js-file-line">                      )</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-snowio-py-LC25" class="blob-code blob-code-inner js-file-line">                      <span class="pl-s1">lines</span> <span class="pl-c1">=</span> []</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-snowio-py-LC26" class="blob-code blob-code-inner js-file-line">              <span class="pl-k">if</span> <span class="pl-s1">lines</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-snowio-py-LC27" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s1">counter</span> <span class="pl-c1">+=</span> <span class="pl-c1">1</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-snowio-py-LC28" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s1">filestream</span> <span class="pl-c1">=</span> <span class="pl-s1">io</span>.<span class="pl-v">BytesIO</span>(<span class="pl-s">b""</span>.<span class="pl-en">join</span>(<span class="pl-s1">lines</span>))</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-snowio-py-LC29" class="blob-code blob-code-inner js-file-line">                  <span class="pl-s1">cursor</span> <span class="pl-c1">=</span> <span class="pl-s1">cursor</span>.<span class="pl-en">execute</span>(</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-snowio-py-LC30" class="blob-code blob-code-inner js-file-line">                      <span class="pl-c1">**</span><span class="pl-s1">cursor_execution_config</span>.<span class="pl-en">dict</span>(),</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-snowio-py-LC31" class="blob-code blob-code-inner js-file-line">                      <span class="pl-s1">file_stream</span><span class="pl-c1">=</span><span class="pl-s1">filestream</span>,</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-snowio-py-LC32" class="blob-code blob-code-inner js-file-line">                  )</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-snowio-py-LC33" class="blob-code blob-code-inner js-file-line">                  <span class="pl-en">debug</span>(<span class="pl-s">f"Final chunk of <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">len</span>(<span class="pl-s1">lines</span>)<span class="pl-kos">}</span></span> lines pushed."</span>)</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-snowio-py-LC34" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">else</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-snowio-py-LC35" class="blob-code blob-code-inner js-file-line">      <span class="pl-s1">cursor</span> <span class="pl-c1">=</span> <span class="pl-s1">cursor</span>.<span class="pl-en">execute</span>(<span class="pl-c1">**</span><span class="pl-s1">cursor_execution_config</span>.<span class="pl-en">dict</span>())</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-snowio-py-LC36" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">cursor</span>, <span class="pl-v">SnowflakeCursor</span>):</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-snowio-py-LC37" class="blob-code blob-code-inner js-file-line">      <span class="pl-c"># SnowflakeExecuteEvent(vars(self.cursor)).log()</span></td>
        </tr>
        <tr>
          <td id="file-snowio-py-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-snowio-py-LC38" class="blob-code blob-code-inner js-file-line">      <span class="pl-s1">logger</span>.<span class="pl-en">info</span>(<span class="pl-s">f"cursor is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">cursor</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-snowio-py-LC39" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">else</span>:</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-snowio-py-LC40" class="blob-code blob-code-inner js-file-line">      <span class="pl-s1">logger</span>.<span class="pl-en">info</span>(<span class="pl-s">f"SQL execution results is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">cursor</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-snowio-py-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-snowio-py-LC41" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">return</span> <span class="pl-s1">self</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/f52be97f86ebba112f9539c7e1eeb0f2/raw/4975ba5d0489fe75011965ea917695cf02015a61/snowio.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/f52be97f86ebba112f9539c7e1eeb0f2#file-snowio-py" class="Link--inTextBlock">
          snowio.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h2>Streaming Data with SFTP using Paramiko</h2><p>The <code>paramiko</code> library allows you to stream data to and from an SFTP server, useful for transferring large files securely.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist131234608\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-push_io-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;push_io.py\&quot;>\n        <tr>\n          <td id=\&quot;file-push_io-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>pythonCopy</span> <span class=pl-s1>code</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>paramiko</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>stream_data_from_sftp</span>(<span class=pl-s1>hostname</span>, <span class=pl-s1>port</span>, <span class=pl-s1>username</span>, <span class=pl-s1>password</span>, <span class=pl-s1>remote_path</span>, <span class=pl-s1>chunk_size</span><span class=pl-c1>=</span><span class=pl-c1>1024</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>transport</span> <span class=pl-c1>=</span> <span class=pl-s1>paramiko</span>.<span class=pl-v>Transport</span>((<span class=pl-s1>hostname</span>, <span class=pl-s1>port</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>transport</span>.<span class=pl-en>connect</span>(<span class=pl-s1>username</span><span class=pl-c1>=</span><span class=pl-s1>username</span>, <span class=pl-s1>password</span><span class=pl-c1>=</span><span class=pl-s1>password</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>sftp</span> <span class=pl-c1>=</span> <span class=pl-s1>paramiko</span>.<span class=pl-v>SFTPClient</span>.<span class=pl-en>from_transport</span>(<span class=pl-s1>transport</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>with</span> <span class=pl-s1>sftp</span>.<span class=pl-en>open</span>(<span class=pl-s1>remote_path</span>, <span class=pl-s>&amp;#39;rb&amp;#39;</span>) <span class=pl-k>as</span> <span class=pl-s1>file</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>while</span> <span class=pl-s1>chunk</span> <span class=pl-c1>:=</span> <span class=pl-s1>file</span>.<span class=pl-en>read</span>(<span class=pl-s1>chunk_size</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>yield</span> <span class=pl-s1>chunk</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>sftp</span>.<span class=pl-en>close</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>transport</span>.<span class=pl-en>close</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Example usage</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>hostname</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;sftp.example.com&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>port</span> <span class=pl-c1>=</span> <span class=pl-c1>22</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>username</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;user&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>password</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;pass&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>remote_path</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;/path/to/large_file&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>for</span> <span class=pl-s1>chunk</span> <span class=pl-c1>in</span> <span class=pl-en>stream_data_from_sftp</span>(<span class=pl-s1>hostname</span>, <span class=pl-s1>port</span>, <span class=pl-s1>username</span>, <span class=pl-s1>password</span>, <span class=pl-s1>remote_path</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Process each chunk</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-push_io-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-push_io-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>chunk</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/945bc3b84789002d340a5cf7445cc568/raw/5828923d63d6df88d169ad245220ed898d0e3112/push_io.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/945bc3b84789002d340a5cf7445cc568#file-push_io-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          push_io.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-16b9b5e1f8b5.css"><div id="gist131234608" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-push_io-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="push_io.py">
        <tbody><tr>
          <td id="file-push_io-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-push_io-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">pythonCopy</span> <span class="pl-s1">code</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-push_io-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">paramiko</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-push_io-py-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-push_io-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">stream_data_from_sftp</span>(<span class="pl-s1">hostname</span>, <span class="pl-s1">port</span>, <span class="pl-s1">username</span>, <span class="pl-s1">password</span>, <span class="pl-s1">remote_path</span>, <span class="pl-s1">chunk_size</span><span class="pl-c1">=</span><span class="pl-c1">1024</span>):</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-push_io-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">transport</span> <span class="pl-c1">=</span> <span class="pl-s1">paramiko</span>.<span class="pl-v">Transport</span>((<span class="pl-s1">hostname</span>, <span class="pl-s1">port</span>))</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-push_io-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">transport</span>.<span class="pl-en">connect</span>(<span class="pl-s1">username</span><span class="pl-c1">=</span><span class="pl-s1">username</span>, <span class="pl-s1">password</span><span class="pl-c1">=</span><span class="pl-s1">password</span>)</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-push_io-py-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">sftp</span> <span class="pl-c1">=</span> <span class="pl-s1">paramiko</span>.<span class="pl-v">SFTPClient</span>.<span class="pl-en">from_transport</span>(<span class="pl-s1">transport</span>)</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-push_io-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-push_io-py-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">with</span> <span class="pl-s1">sftp</span>.<span class="pl-en">open</span>(<span class="pl-s1">remote_path</span>, <span class="pl-s">'rb'</span>) <span class="pl-k">as</span> <span class="pl-s1">file</span>:</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-push_io-py-LC10" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">while</span> <span class="pl-s1">chunk</span> <span class="pl-c1">:=</span> <span class="pl-s1">file</span>.<span class="pl-en">read</span>(<span class="pl-s1">chunk_size</span>):</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-push_io-py-LC11" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">yield</span> <span class="pl-s1">chunk</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-push_io-py-LC12" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-push_io-py-LC13" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">sftp</span>.<span class="pl-en">close</span>()</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-push_io-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">transport</span>.<span class="pl-en">close</span>()</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-push_io-py-LC15" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-push_io-py-LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Example usage</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-push_io-py-LC17" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">hostname</span> <span class="pl-c1">=</span> <span class="pl-s">'sftp.example.com'</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-push_io-py-LC18" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">port</span> <span class="pl-c1">=</span> <span class="pl-c1">22</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-push_io-py-LC19" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">username</span> <span class="pl-c1">=</span> <span class="pl-s">'user'</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-push_io-py-LC20" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">password</span> <span class="pl-c1">=</span> <span class="pl-s">'pass'</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-push_io-py-LC21" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">remote_path</span> <span class="pl-c1">=</span> <span class="pl-s">'/path/to/large_file'</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-push_io-py-LC22" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> <span class="pl-s1">chunk</span> <span class="pl-c1">in</span> <span class="pl-en">stream_data_from_sftp</span>(<span class="pl-s1">hostname</span>, <span class="pl-s1">port</span>, <span class="pl-s1">username</span>, <span class="pl-s1">password</span>, <span class="pl-s1">remote_path</span>):</td>
        </tr>
        <tr>
          <td id="file-push_io-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-push_io-py-LC23" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Process each chunk</span></td>
        </tr>
        <tr>
          <td id="file-push_io-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-push_io-py-LC24" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">chunk</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/945bc3b84789002d340a5cf7445cc568/raw/5828923d63d6df88d169ad245220ed898d0e3112/push_io.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/945bc3b84789002d340a5cf7445cc568#file-push_io-py" class="Link--inTextBlock">
          push_io.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>By using these libraries and methods, you can effectively implement streaming data interfaces to handle large datasets efficiently across various platforms and services.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Becoming a 1.5X YAML engineer]]></title><description><![CDATA[How to use VScode plugins combined with JSON schemas to build your own YAML validators.]]></description><link>https://www.blog.zelytics.tech/p/becoming-a-15x-yaml-engineer</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/becoming-a-15x-yaml-engineer</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Sun, 30 Jun 2024 12:43:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5rS0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As an engineer, you will work a LOT with yaml files. Whether it is configuring infrastructure through kubernetes, configuring data models through dbt or configuring CI/CD with github actions. Many frameworks which use yaml for configuration have their own formatters and validators to figure out if your yaml specification is correct, but what if you need more custom behavior? If you&#8217;re working with VSCode, there is a simple way to create custom yaml validators through the use of the YAML plugin by Redhat combined with JSON schemas.</p><h1>JSON schemas can represent YAML schemas</h1><p>The first thing to highlight is that, at least since the 2009 specification of <a href="https://yaml.org/spec/1.2.2/">yaml 1.2</a> , yaml is a strict superset of JSON. What does this mean in practise? This means that proper implementation of the YAML 1.2 protocol will yield a parser that can parse both JSON and YAML. In other words, YAML can represent anything that can be represented in JSON but more. Conversely, this means we can use JSON tools to represent a subset of YAML specifications.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>For the validation of JSON files, the <a href="https://json-schema.org/">JSON schema</a> specification allows to express expected schemas for a JSON file through another JSON file in JSON schema format. We can use this specification to define the schema for a json file representation of a yaml file. Consider the following example yaml file:</p><pre><code><code>app:
  name: MyApp
  version: 1.0.0
  debug: true
  database:
    host: localhost
    port: 5432
    username: user
    password: pass
  features:
    - authentication
    - logging
    - analytics

</code></code></pre><p>The JSON equivalent of this file would look something like:</p><pre><code><code>{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "debug": true,
    "database": {
      "host": "localhost",
      "port": 5432,
      "username": "user",
      "password": "pass"
    },
    "features": [
      "authentication",
      "logging",
      "analytics"
    ]
  }
}
</code></code></pre><p>The json schema that would represent the above schema looks as follows in json-schema format:</p><pre><code><code>{
  "$schema": "&lt;http://json-schema.org/draft-07/schema#&gt;",
  "type": "object",
  "properties": {
    "app": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "version": {
          "type": "string",
          "pattern": "^[0-9]+\\\\.[0-9]+\\\\.[0-9]+$"
        },
        "debug": {
          "type": "boolean"
        },
        "database": {
          "type": "object",
          "properties": {
            "host": {
              "type": "string"
            },
            "port": {
              "type": "integer",
              "minimum": 1,
              "maximum": 65535
            },
            "username": {
              "type": "string"
            },
            "password": {
              "type": "string"
            }
          },
          "required": ["host", "port", "username", "password"]
        },
        "features": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": ["name", "version", "debug", "database", "features"]
    }
  },
  "required": ["app"]
}
</code></code></pre><p>As you can probably tell, the json schema defines an expected schema for a json file. The json schema specification allows for many different kinds of validation mechanisms. In the above example, you can see that it&#8217;s possible to indicate which keys an object should at least have through <code>required</code> . You can also see that we can define validations for specific fields such as a <code>minimum</code> and <code>maximum</code> port number and a regular expression <code>pattern</code> for version.</p><p>Considering the above, we can use json schemas to represent validation rules for yaml files, but how can we easily integrate this in our interactive development environment? If you are using VScode, the YAML extension by RedHat offers a very simple solution.</p><h1>Custom YAML validation with JSON schemas in VScode</h1><p>The first step is to install the YAML extension <code>redhat.vscode-yaml</code> in VScode</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5rS0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5rS0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 424w, https://substackcdn.com/image/fetch/$s_!5rS0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 848w, https://substackcdn.com/image/fetch/$s_!5rS0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 1272w, https://substackcdn.com/image/fetch/$s_!5rS0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5rS0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png" width="1456" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:434346,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5rS0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 424w, https://substackcdn.com/image/fetch/$s_!5rS0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 848w, https://substackcdn.com/image/fetch/$s_!5rS0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 1272w, https://substackcdn.com/image/fetch/$s_!5rS0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56bea81-1200-43dc-b1dd-67a535dd285a_2000x1055.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now, in your <code>settings.json</code> file for VScode, you can create a map between json schema and yaml files to validate with that json schema. So for example:</p><pre><code><code>"yaml.schemas": {
&#9;"&lt;absolute path to schema&gt;": [
&#9;&#9;"/**/*app.y*ml",
&#9;]
}
</code></code></pre><p>The above will tell us that the json schema <code>custom_app_yaml_schema.json</code> will be used to validate any YAML file on our system that ends with <code>app.yaml</code> or <code>app.yml</code> (though technically the regex would pick up something like <code>app.ybml</code> too but that&#8217;s besides the point).</p><p>Now, let&#8217;s take the above json schema and use it with the <code>app.yml</code> we&#8217;ve described before.</p><p>Now to make potential validation errors more obvious when I open the yaml file, I add another extension called <code>usernamehw.errorlens</code> which adds a more obvious highlight for errors:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FeFu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FeFu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 424w, https://substackcdn.com/image/fetch/$s_!FeFu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 848w, https://substackcdn.com/image/fetch/$s_!FeFu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 1272w, https://substackcdn.com/image/fetch/$s_!FeFu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FeFu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png" width="1456" height="511" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:511,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:274493,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FeFu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 424w, https://substackcdn.com/image/fetch/$s_!FeFu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 848w, https://substackcdn.com/image/fetch/$s_!FeFu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 1272w, https://substackcdn.com/image/fetch/$s_!FeFu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff7c60d-0de8-4a54-9495-003fae6dc55b_2000x702.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now, let&#8217;s say we purposefully create some alterations of this yaml file that don&#8217;t fit the schema. We now get real time feedback from the JSON schema on our invalid configuration!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xEpq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xEpq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 424w, https://substackcdn.com/image/fetch/$s_!xEpq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 848w, https://substackcdn.com/image/fetch/$s_!xEpq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 1272w, https://substackcdn.com/image/fetch/$s_!xEpq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xEpq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png" width="1456" height="767" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:767,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:387454,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xEpq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 424w, https://substackcdn.com/image/fetch/$s_!xEpq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 848w, https://substackcdn.com/image/fetch/$s_!xEpq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 1272w, https://substackcdn.com/image/fetch/$s_!xEpq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc2451c-caa6-40d2-87d6-f51f28b3bec8_2000x1054.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Pretty cool hu?</p><p>This can be a very powerful tool in your IDE. In the rest of this article we will go a little bit more in depth into json schemas and how we can work with them to configure various kinds of validations.</p><h1>JSON schema customizations</h1><p>JSON schemas can have a bit of a learning curve when it comes to writing correct expressions. There have also been <a href="https://json-schema.org/specification">quite a few releases</a> over the years when it comes to specifications. Please keep in mind what schema your tooling supports. As of today, the YAML extension support schemas of format draft 7, so I will keep to functionality specific to that draft.</p><p><a href="https://json-schema.org/learn/getting-started-step-by-step">json-schema documentation</a> is pretty all encompassing when it comes to capabilities. In this section I want to highlight a few parts of the specification that have been useful for me so far:</p><h2>The root elements</h2><p>Each json schema document will have a few minimum root elements:</p><ul><li><p><code>title</code> : The title of the document</p></li><li><p><code>$schema</code> : A url to the json schema specification.</p></li></ul><p>The <code>$schema</code> element here points to any of the official json draft specifications. We have actually seen one in the example schema before: <a href="https://json-schema.org/draft-07/schema">https://json-schema.org/draft-07/schema</a>. Go ahead, click that link. You will notice that the schema is defined in a json-schema like format!</p><h2>Json schema types</h2><p>The basic non-hierarchical data types are <code>string</code>, <code>integer</code>, <code>number</code>, <code>boolean</code> and <code>null</code>. These are types that cannot have nested or recursive interpretations. For those use cases, there&#8217;s <code>arrays</code> (equivalent to a python list or tuple) and <code>objects</code> (equivalent to a python dictionary). Let&#8217;s go into a little more detail of each.</p><h3>Null and boolean</h3><p>The simplest of these are <code>null</code> and <code>boolean</code> which have straightforward meanings for each programming language interface provided to json schema. For example, <code>null</code> will evaluate to <code>None</code> in python.</p><h3>Numeric types</h3><p><code>Integers</code> and <code>numbers</code> have more validation available to them. It&#8217;s possible to define a number must be a <code>multipleOf</code> a certain factor. The example below will only accept multiples of ten:</p><pre><code><code>{
  "type": "number",
  "multipleOf" : 10
}</code></code></pre><p>Ranges of numbers are specified using a combination of the&nbsp;<code>minimum</code>&nbsp;and&nbsp;<code>maximum</code>&nbsp;keywords, (or&nbsp;<code>exclusiveMinimum</code>&nbsp;and&nbsp;<code>exclusiveMaximum</code>&nbsp;for expressing exclusive range).</p><p>If&nbsp;<em>x</em>&nbsp;is the value being validated, the following must hold true:</p><p><em>x</em>&nbsp;&#8805;&nbsp;<code>minimum</code></p><p><em>x</em>&nbsp;&gt;&nbsp;<code>exclusiveMinimum</code></p><p><em>x</em>&nbsp;&#8804;&nbsp;<code>maximum</code></p><p><em>x</em>&nbsp;&lt;&nbsp;<code>exclusiveMaximum</code></p><p>While you can specify both of&nbsp;<code>minimum</code>&nbsp;and&nbsp;<code>exclusiveMinimum</code>&nbsp;or both of&nbsp;<code>maximum</code>&nbsp;and&nbsp;<code>exclusiveMaximum</code>, it doesn't really make sense to do so.</p><p>The following example will allow values 0 through 99:</p><pre><code><code>{
  "type": "number",
  "minimum": 0,
  "exclusiveMaximum": 100
}</code></code></pre><h3>String types</h3><p>String types are the most flexible type. Strings have a variety of validation tools to their disposal.</p><p>The simplest validation tool is <code>length</code> .</p><p>The length of a string can be constrained using the&nbsp;<code>minLength</code>&nbsp;and&nbsp;<code>maxLength</code>&nbsp;<a href="https://json-schema.org/learn/glossary#keyword">keywords</a>. For both keywords, the value must be a non-negative number.</p><p>The following defines that a string must be between 2 and 3 characters long:</p><pre><code><code>{
  "type": "string",
  "minLength": 2,
  "maxLength": 3
}</code></code></pre><p><code>Format</code> can be used to define that a string has a certain format like an e-mail address. Do note that support for various formats depends on the implementation of the json schema at hand. The &#8220;canonical&#8221; supported formats as per specification can be found <a href="https://json-schema.org/understanding-json-schema/reference/string#built-in-formats:~:text=Built%2Din%20formats-,%C2%B6,-The%20following%20is">here</a>.</p><p>For example, if we have an e-mail, we may define it as:</p><pre><code><code>{
  "type": "string",
  "format": "email",
}</code></code></pre><p>Finally, for the most flexibility we can user regular expressions through the <code>pattern</code> keyword. Keep in mind that json schema maintains a specific implementation of regular expressions which can be viewed <a href="https://json-schema.org/understanding-json-schema/reference/regular_expressions">here</a>.</p><p>For example, if we want to define a string should start with <code>{</code> and end with <code>}</code> it can be defined as follows:</p><pre><code><code> {
   "type": "string",
   "pattern": "^\\\\{\\\\{(.|[\\\\r\\\\n])*\\\\}\\\\}$",
  }
</code></code></pre><h2>Array</h2><p>Arrays are the first type that we discuss that define more than one element.</p><p>There are two ways in which arrays are generally used in JSON:</p><ul><li><p><strong>List validation:</strong>&nbsp;a sequence of arbitrary length where each item matches the same&nbsp;<a href="https://json-schema.org/learn/glossary#schema">schema</a>.</p></li><li><p><strong>Tuple validation:</strong>&nbsp;a sequence of fixed length where each item may have a different schema. In this usage, the index (or location) of each item is meaningful as to how the value is interpreted. (This usage is often given a whole separate type in some programming languages, such as Python's&nbsp;<code>tuple</code>).</p></li></ul><p>There&#8217;s a few keywords that are important to understand for arrays.</p><h3>Validating the type of all array elements with <code>items</code> and <code>contains</code></h3><p><code>Items</code> can be used to define what the type of the elements in the list should be. For example, if we only want numbers in a list we can define that as:</p><pre><code><code>{
  "type": "array",
  "items": {
    "type": "number"
  }
}</code></code></pre><p>If we want at least one element to be a number instead, we can use <code>contains</code> to define that schema:</p><pre><code><code>{
  "type": "array",
  "contains": {
    "type": "number"
  }
}</code></code></pre><h3>Tuple validation using <code>PrefixItems</code></h3><p>For tuple validation, we can use the keyword <code>PrefixItems</code> to determine the required schema of the tuple elements. Let&#8217;s say we have a tuple that defines an element <code>street name</code> and <code>street type</code> . For <code>street name</code> we just want to have a string. For <code>street type</code> we want to use a string from a specific set of strings. We can accomplish the latter through the <code>enum</code> keyword. This results into the following schema component:</p><pre><code><code>{
  "type": "array",
  "prefixItems": [
    { "type": "string" },
    { "enum": ["Street", "Avenue", "Boulevard"] },
  ]
}</code></code></pre><p>We can use the <code>items</code> keyword as mentioned in the previous section to define more specific constraints for elements. For example, Setting <code>items</code> to <code>false</code> disallows extra elements to be added in this list:</p><pre><code><code>{
  "type": "array",
  "prefixItems": [

    { "enum": ["Street", "Avenue", "Boulevard"] },
    { "enum": ["NW", "NE", "SW", "SE"] }
  ],
  "items": false
}</code></code></pre><p>Crucially, <code>items</code> accepts subschemas as well and with that, <code>arrays</code> are the first type we described in this article that can act as a &#8220;container&#8221; for other types:</p><pre><code><code>{
  "type": "array",
  "prefixItems": [
    { "enum": ["Street", "Avenue", "Boulevard"] },
    { "enum": ["NW", "NE", "SW", "SE"] }
  ],
  "items": { "type": "string" }
}</code></code></pre><p>There are more keywords that can be used with <code>arrays</code> but for the sake of brevity we won&#8217;t go over those here.</p><h3>Objects</h3><p>Objects are the mapping type in JSON. They map "keys" to "values". In JSON, the "keys" must always be strings. Each of these pairs is conventionally referred to as a "property".</p><p>The properties (key-value pairs) on an object are defined using the&nbsp;<code>properties</code>&nbsp;<a href="https://json-schema.org/learn/glossary#keyword">keyword</a>. The value of&nbsp;<code>properties</code>&nbsp;is an object, where each key is the name of a property and each value is a&nbsp;<a href="https://json-schema.org/learn/glossary#schema">schema</a>&nbsp;used to validate that property. Any property that doesn't match any of the property names in the&nbsp;<code>properties</code>&nbsp;keyword is ignored by this keyword.</p><p>Let&#8217;s take the same example as the tuple validation example specified in the <code>array</code> section. We have a <code>street_name</code> and a <code>street_type</code> . In an object, we can define this as follows:</p><pre><code><code>{
  "type": "object",
  "properties": {
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  }
}</code></code></pre><p><code>Objects</code> have different keywords that encompass similar behavior to those found in <code>arrays</code> , however, One thing that objects are particularly well suited for is creating more complex schema compositions. We will go into more complex schema generation into the following sections because there is some context to be understood before diving into that.</p><h2>Structuring a Complex Schema in JSON Schema: The URI model</h2><p>When working with JSON Schema, it's advantageous to structure your schemas into reusable components, much like how you would structure your code with functions and modules. This approach not only promotes reusability but also makes your schemas easier to maintain and extend.</p><h3>Schema Identification</h3><p>Schemas are identified using non-relative URIs, which act as unique identifiers. Although schemas are not required to have an identifier, having one allows you to reference them from other schemas. In this context, schemas without identifiers are termed "anonymous schemas."</p><h3>Base URI and $id</h3><p>The base URI of a schema is crucial for resolving relative references. By default, the base URI is the retrieval URI of the schema. You can explicitly set the base URI using the <code>$id</code> keyword. For example:</p><pre><code><code>{
  "$id": "&lt;https://example.com/schemas/address&gt;",
  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}</code></code></pre><p>In this schema, <code>$id</code> sets the base URI to <code>https://example.com/schemas/address</code>. Please do note that this does NOT neccecarily mean it is fetched from this webaddress.</p><p>Even though schemas are identified by URIs, those identifiers are not necessarily network-addressable. They are just identifiers. Generally,&nbsp;<a href="https://json-schema.org/learn/glossary#implementation">implementations</a>&nbsp;don't make HTTP requests (<code>https://</code>) or read from the file system (<code>file://</code>) to fetch schemas. Instead, they provide a way to load schemas into an internal schema database. When a schema is referenced by it's URI identifier, the schema is retrieved from the internal schema database.</p><p>The URI <code>https://example.com/schemas/address#/properties/street_address</code> identifies the <code>street_address</code> property in the schema.</p><h3>$ref for Reusing Schemas</h3><p>The <code>$ref</code> keyword allows you to reuse existing schemas.</p><p>Example:</p><pre><code><code>{
  "$id": "&lt;https://example.com/schemas/customer&gt;",
  "type": "object",
  "properties": {
    "first_name": { "type": "string" },
    "last_name": { "type": "string" },
    "shipping_address": { "$ref": "&lt;https://example.com/schemas/address&gt;" },
    "billing_address": { "$ref": "&lt;https://example.com/schemas/address&gt;" }
  },
  "required": ["first_name", "last_name", "shipping_address", "billing_address"]
}</code></code></pre><p>Here, both <code>shipping_address</code> and <code>billing_address</code> reference the same address schema, ensuring consistency and reducing redundancy.</p><h3>$defs for Local Subschemas</h3><p>Use <code>$defs</code> to define subschemas that are intended for reuse within the same schema document. This keeps your schema organized and readable.</p><p>Example:</p><pre><code><code>{
  "$id": "&lt;https://example.com/schemas/customer&gt;",
  "type": "object",
  "properties": {
    "first_name": { "$ref": "#/$defs/name" },
    "last_name": { "$ref": "#/$defs/name" },
    "shipping_address": { "$ref": "&lt;https://example.com/schemas/address&gt;" },
    "billing_address": { "$ref": "&lt;https://example.com/schemas/address&gt;" }
  },
  "required": ["first_name", "last_name", "shipping_address", "billing_address"],
  "$defs": {
    "name": { "type": "string" }
  }
}</code></code></pre><h3>Recursive Schemas</h3><p>Schemas can be recursive, referring to themselves, which is useful for representing hierarchical structures like trees.</p><p>Example:</p><pre><code><code>{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "children": {
      "type": "array",
      "items": { "$ref": "#" }
    }
  }
}</code></code></pre><p>This schema defines a recursive structure where each <code>children</code> array can contain items that follow the same schema.</p><h3>Bundling Schemas</h3><p>For distribution, you might want to bundle multiple schemas into a single document. This can be done using <code>$id</code> in subschemas, creating a compound schema document.</p><p>Example:</p><pre><code><code>{
  "$id": "&lt;https://example.com/schemas/customer&gt;",
  "$schema": "&lt;https://json-schema.org/draft/2020-12/schema&gt;",
  "type": "object",
  "properties": {
    "first_name": { "type": "string" },
    "last_name": { "type": "string" },
    "shipping_address": { "$ref": "#/$defs/address" },
    "billing_address": { "$ref": "#/$defs/address" }
  },
  "required": ["first_name", "last_name", "shipping_address", "billing_address"],
  "$defs": {
    "address": {
      "$id": "&lt;https://example.com/schemas/address&gt;",
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city": { "type": "string" },
        "state": { "$ref": "#/definitions/state" }
      },
      "required": ["street_address", "city", "state"],
      "definitions": {
        "state": { "enum": ["CA", "NY", "... etc ..."] }
      }
    }
  }
}
</code></code></pre><p>Bundling schemas this way ensures all necessary components are included in a single document, making it easier to share and maintain.</p><h3>Applying binary operators on schemas</h3><p>The keywords used to combine schemas are:</p><ul><li><p><code>allOf</code>: (AND) Must be valid against&nbsp;<em>all</em>&nbsp;of the&nbsp;<a href="https://json-schema.org/learn/glossary#subschema">subschemas</a></p></li><li><p><code>anyOf</code>: (OR) Must be valid against&nbsp;<em>any</em>&nbsp;of the subschemas</p></li><li><p><code>oneOf</code>: (XOR) Must be valid against&nbsp;<em>exactly one</em>&nbsp;of the subschemas</p></li></ul><p>All of these keywords must be set to an array, where each item is a schema. Be careful with recursive schemas as they can exponentially increase processing times.</p><p>In addition, there is:</p><ul><li><p><code>not</code>: (NOT) Must&nbsp;<em>not</em>&nbsp;be valid against the given schema</p></li></ul><p>This can be used as follows for example:</p><pre><code><code>{
  "allOf": [
    { "type": "string" },
    { "maxLength": 5 }
  ]
}</code></code></pre><h1>Wrapping up</h1><p>This article went into depth on how custom validators can be configured for any set of <code>YAML</code> files with custom json schemas and the yaml extension on VScode. We went in depth into how JSON schemas can be constructed to validate various types of documents. In a next article, we will focus on applying this to a specific use case for data (analytics) engineering for maintaining YAML state of <code>dbt</code> yaml files by showing how we can interface with these validations through python as well.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[A deep dive into the snowflake python API]]></title><description><![CDATA[Developing data applications on your python data platform of choice]]></description><link>https://www.blog.zelytics.tech/p/a-deep-dive-into-the-snowflake-python</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/a-deep-dive-into-the-snowflake-python</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Mon, 10 Jun 2024 08:12:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Intro</h2><p>When you&#8217;re working with snowflake as a data engineer, chances are you will be developing applications and capabilities of your data platform on top of snowflake.</p><p>At the very least, you will be interacting with third party tools that directly integrate with snowflake themselves such as data transformations tools like dbt, reporting tools like looker and data orchestrators such as airflow.</p><p>What underlies all of these is interacting with the snowflake platform through a programmatic manner. As such, we can view the development of snowflake based external applications as follows:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Zh-q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Zh-q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 424w, https://substackcdn.com/image/fetch/$s_!Zh-q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 848w, https://substackcdn.com/image/fetch/$s_!Zh-q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 1272w, https://substackcdn.com/image/fetch/$s_!Zh-q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Zh-q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png" width="1456" height="1712" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1712,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:944350,&quot;alt&quot;:&quot;an overview of the snowflake ecosystem&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="an overview of the snowflake ecosystem" title="an overview of the snowflake ecosystem" srcset="https://substackcdn.com/image/fetch/$s_!Zh-q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 424w, https://substackcdn.com/image/fetch/$s_!Zh-q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 848w, https://substackcdn.com/image/fetch/$s_!Zh-q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 1272w, https://substackcdn.com/image/fetch/$s_!Zh-q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e29dd5-4c30-4771-a691-d548aaf8a784_2000x2352.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A very high level overview of the snowflake ecosystem. creds to: <a href="https://www.flaticon.com/authors/rakibgraphics">https://www.flaticon.com/authors/rakibgraphics</a> and <a href="https://docs.snowflake.com/en/user-guide/ecosystem">https://docs.snowflake.com/en/user-guide/ecosystem</a></figcaption></figure></div><p>There is the snowflake platform with it&#8217;s capabilities which we can interface with in a few ways:</p><ul><li><p>Through an UI such as snowflake worksheets and snowflake snowsight</p></li><li><p>Through the CLI interface snowSQL</p></li><li><p>Through programmatic interfaces in various programming languages (to view all available connectors, check <a href="https://github.com/snowflakedb">https://github.com/snowflakedb</a>).</p></li></ul><p>Almost every external application, SaaS or integration will use a programmatic interface or snowflake connector in some way shape or form to build out functionality.</p><p>An example of this would be the data transformation tool dbt. Dbt has a snowflake integration, but under the hood it will use the snowflake connector for python to manage executing SQL commands against snowflake.</p><p>Another example would be the snowflake plugin in VScode which uses the nodeJS connector to execute various SQL commands based on UI input.</p><p>Considering this, understanding the programmatic interface with snowflake allows to:</p><ul><li><p>Build custom data applications for your data platform</p></li><li><p>Understand and debug (snowflake) third party tools</p></li><li><p>Integrate Snowflake more natively with distributed computing on your data orchestrator</p></li><li><p>Build out capabilities that are not quite handled by higher level APIs such as snowpark</p></li><li><p>Understand the fundamental principles of how snowflake handles queries, results and more.</p></li></ul><h1>The components of a snowflake connector: The python example</h1><p>In this article we&#8217;ll be exploring the python connector to understand snowflake connectors in general. As each connector implements the same fundamentals, we can use the example of python to understand the most fundamental principles of all connectors.</p><p>Fundamentally, there are two main components to control for in the connector:</p><ul><li><p>The connection</p></li><li><p>The cursor</p></li></ul><p>The connection configuration determines how you connect to snowflake from python.</p><p>The cursor is a database object used to retrieve, manipulate, and navigate through a snowflake result set. It&#8217;s used to send SQL instructions to snowflake as well as store results from any execute method performed.</p><p>The cursor has execution method that determine what SQL operation we actually execute against snowflake and how we process the result back into python.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7U-9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7U-9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 424w, https://substackcdn.com/image/fetch/$s_!7U-9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 848w, https://substackcdn.com/image/fetch/$s_!7U-9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 1272w, https://substackcdn.com/image/fetch/$s_!7U-9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7U-9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png" width="1456" height="749" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:749,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:398267,&quot;alt&quot;:&quot;The main components of the snowflake connector are a connection and a cursor.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The main components of the snowflake connector are a connection and a cursor." title="The main components of the snowflake connector are a connection and a cursor." srcset="https://substackcdn.com/image/fetch/$s_!7U-9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 424w, https://substackcdn.com/image/fetch/$s_!7U-9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 848w, https://substackcdn.com/image/fetch/$s_!7U-9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 1272w, https://substackcdn.com/image/fetch/$s_!7U-9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F312be216-cb36-460d-b928-8a92dbe3113a_2564x1319.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The main components of the snowflake connector and how the interact with snowflake. </figcaption></figure></div><h2>Connection</h2><p>This component will dictate how the python connector can connect to your snowflake account. The relevant python class is <a href="https://github.com/snowflakedb/snowflake-connector-python/blob/main/src/snowflake/connector/connection.py#L309">SnowflakeConnection</a>, which will handle most of the configurations around connecting to snowflake and some more. There is a lot of things that we can set as of current <strong>release 3.10.1.</strong> Instead of going through every single setting, we will go through a few conceptual subcategories and go over the most important attributes you may or may not want to set. For a more extensive deep dive, feel free to refer to the source code of <a href="https://github.com/snowflakedb/snowflake-connector-python/blob/main/src/snowflake/connector/connection.py#L309">SnowflakeConnection</a>.</p><h3>Defining security and authentication parameters</h3><p>I will start with security of snowflake connections as most settings around connectivity revolve in some way, shape or form around security. Considering the <a href="https://www.wired.com/story/snowflake-breach-advanced-auto-parts-lendingtree/">recent security breaches</a> on the Snowflake platform of several large organisations, it is more relevant than ever to pay attention to this.</p><p>To connect to an <code>account</code> you will need the correct account identifier <a href="https://docs.snowflake.com/en/user-guide/organizations-connect">based on your authentication method</a>. When connecting with a username, use the <code>user</code> attribute to define the snowflake username to log in with.</p><p>The most significant attribute is <code>authenticator</code>. This attribute will determine what authentication method is used to authenticate to snowflake. The table below shows the currently supported <a href="https://github.com/snowflakedb/snowflake-connector-python/blob/main/src/snowflake/connector/auth/__init__.py#L17-L27">first-party authentication methods</a> you&#8217;ll probably use most alongside some relevant details for each.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W-JV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W-JV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 424w, https://substackcdn.com/image/fetch/$s_!W-JV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 848w, https://substackcdn.com/image/fetch/$s_!W-JV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 1272w, https://substackcdn.com/image/fetch/$s_!W-JV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W-JV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png" width="1456" height="397" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:397,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:89457,&quot;alt&quot;:&quot;primary snowflake authentication methods&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="primary snowflake authentication methods" title="primary snowflake authentication methods" srcset="https://substackcdn.com/image/fetch/$s_!W-JV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 424w, https://substackcdn.com/image/fetch/$s_!W-JV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 848w, https://substackcdn.com/image/fetch/$s_!W-JV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 1272w, https://substackcdn.com/image/fetch/$s_!W-JV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffe59f2-34ff-42da-8b1d-955dca8f7137_1554x424.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Primary authentication methods for connecting to Snowflake</figcaption></figure></div><p>Username and password alone are vulnerable to various attacks such as phishing, brute force, and credential stuffing. Passwords can be weak, reused across multiple sites, and stolen in data breaches.</p><p>SSH key pairs are more secure than passwords because they use public key cryptography. The private key is kept secret and the public key is shared. However, the security relies heavily on the protection of the private key. If the private key is compromised or infrequently rotated, the security is significantly weakened.</p><p>Combining username and password with MFA significantly enhances security. Even if the password is compromised, the attacker would also need access to the second factor (such as a physical token, mobile app, or biometrics), making unauthorized access much more difficult. However, using a password still confers some of the weaknesses of general user+pass flows.</p><p>Single Sign-On (SSO) via Okta provides a higher level of security through centralized authentication. It often includes robust features like strong password policies, adaptive multi-factor authentication (MFA), and anomaly detection. The downside is that the security of the entire system depends on the security of the SSO provider. These providers are <a href="https://www.reuters.com/technology/cybersecurity/okta-says-hackers-stole-data-all-customer-support-users-cyber-breach-2023-11-29/">prime targets for hacks</a>. Additionally, there may be additional cost involved with these solutions, often more suited to enterprise users.</p><p>Chances are, if you work in a company of any decent size, there will be some sort of proxy or VPN solution used to connect to things. For proxies, it&#8217;s possible to set things up through the attributes <code>proxy_host</code>, <code>proxy_port</code>, <code>proxy_user</code> and <code>proxy_password</code>. For VPNs, configuration will depend from VPN to VPN provider but usually, it&#8217;s possible to set a <a href="https://www.techtarget.com/searchsecurity/definition/certificate-authority#:~:text=A%20certificate%20authority%20(CA)%20is,trust%20in%20content%20delivered%20online">CA certificate</a> for the VPN of choice. The snowflake connector uses pythons standard certificate store so a certificate can be simply set as:</p><pre><code><code>cat public_cert.crt &gt;&gt; $(python -m certifi)
pip config set global.cert $(python -m certifi)</code></code></pre><p>We may delve deeper in the future in topics around these security protocols, but these things should give you a rough idea how to implement these common setups.</p><p>One last thing to note about security is that there are various security options available such as <code>insecure mode</code> , <code>ocsp_fail_open</code> , <code>port</code> and more. The best advice here is to never alter these values. If you find yourself in the need to configure these sorts of settings to resolve issues around connectivity, it&#8217;s a lot more prudent to find the actual root cause of your issue rather than downgrading the security of your application to make a connection.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3DI7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3DI7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 424w, https://substackcdn.com/image/fetch/$s_!3DI7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 848w, https://substackcdn.com/image/fetch/$s_!3DI7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 1272w, https://substackcdn.com/image/fetch/$s_!3DI7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3DI7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png" width="1456" height="1241" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1241,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:396514,&quot;alt&quot;:&quot;snowflake authentication methods&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="snowflake authentication methods" title="snowflake authentication methods" srcset="https://substackcdn.com/image/fetch/$s_!3DI7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 424w, https://substackcdn.com/image/fetch/$s_!3DI7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 848w, https://substackcdn.com/image/fetch/$s_!3DI7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 1272w, https://substackcdn.com/image/fetch/$s_!3DI7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc700de9-01eb-44f6-8ea5-5a086d42c295_1804x1538.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Authentication methods to snowflake.</figcaption></figure></div><p></p><h3>Defining database parameters</h3><p>Within the connection configuration, there are several attributes that map to database components that you would typically use when interacting with snowflake. Using <code>database</code> , <code>schema</code> , <code>warehouse</code> and <code>role</code> we can define the characteristics of our database connection. This will follow <a href="https://docs.snowflake.com/en/user-guide/security-access-control-overview">snowflake role based access control</a> configurations in your account. If you want the snowflake connector to check if your combination of database parameters are valid for your snowflake account, you can set <code>validate_default_parameters</code> to <code>true</code> which will give you an error if you try to connect with incorrect database parameters.</p><h3>Defining how API data is parsed in python</h3><p>When interacting with snowflake, at the core we&#8217;re exchanging data over the web which means we will have some sort of serialization and deserialization happening between the client and server. As such, there is a lot of &#8220;translation&#8221; happening between Snowflake API compatible formats and objects that are native to python. There&#8217;s a few important parameters to understand here, though you may not need to alter them often.</p><p>The python snowflake connector will handle database exceptions with <a href="https://github.com/snowflakedb/snowflake-connector-python/blob/5e61c94691c72e6e7e7a7c83849949a188b72172/src/snowflake/connector/errors.py#L32">a custom exception class</a> that inherits from python exceptions. Essentially, this exception class will parse database errors from the API responses and convert them to python exceptions such that your python application can have native exceptions on database errors. If you wish to change the parsing, formatting or other handling of errors, you can write your own classes and overwrite with the <code>errorhandler</code> attribute.</p><p>When it comes to converting snowflake API types to python types, this is handled by a <a href="https://github.com/snowflakedb/snowflake-connector-python/blob/main/src/snowflake/connector/converter.py#L154">SnowflakeConverter</a> class. Simply put, these classes determine how to translate types from API format to python. Generally this is handled pretty well, but, in some cases it may be useful to overwrite this behavior when you are developing your data platform if you are using certain libraries and data constructs that are not part of the standard library. You may for example want to add additional type validation through pydantic. To overwrite the converter class, you can use <code>converter_class</code> in your connection config.</p><p>The python snowflake connector can result many different data types. We will dive a bit deeper into different results data types later but suffice to say that we can influence how are results are returned to us through parameters in the connection class. Two settings that come to mind are <code>json_result_force_utf8_decoding</code> which will force the connector to decode all json strings as <code>utf8</code> when returning json and <code>client_prefetch_threads</code> which impacts how many threads are used to fetch the first set of results. Again, we will get back to these in depth in a bit, but just be aware that some result parsing settings are configured at the connection level.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pnSl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pnSl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 424w, https://substackcdn.com/image/fetch/$s_!pnSl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 848w, https://substackcdn.com/image/fetch/$s_!pnSl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 1272w, https://substackcdn.com/image/fetch/$s_!pnSl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pnSl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png" width="1456" height="1177" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1177,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:252746,&quot;alt&quot;:&quot;control how data is converted from snowflake to python in the snowflake python connector&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="control how data is converted from snowflake to python in the snowflake python connector" title="control how data is converted from snowflake to python in the snowflake python connector" srcset="https://substackcdn.com/image/fetch/$s_!pnSl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 424w, https://substackcdn.com/image/fetch/$s_!pnSl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 848w, https://substackcdn.com/image/fetch/$s_!pnSl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 1272w, https://substackcdn.com/image/fetch/$s_!pnSl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c286325-b5e4-4c20-a56a-e4502b1d079e_1490x1204.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Control how snowflake data is converted to python objects.</figcaption></figure></div><h3>Defining session and timeout parameters</h3><p>When connecting to snowflake to execute some SQL statements, we can view the time from start to end of the connection as a session. As such, it&#8217;s prudent to consider how we bound these sessions to prevent issues like hanging connections.</p><p>Most relevant parameters around this concept are timeouts. In the snowflake connection configuration we can set a few different kinds of timeouts:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JLwj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JLwj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 424w, https://substackcdn.com/image/fetch/$s_!JLwj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 848w, https://substackcdn.com/image/fetch/$s_!JLwj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 1272w, https://substackcdn.com/image/fetch/$s_!JLwj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JLwj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png" width="1456" height="315" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:315,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:85757,&quot;alt&quot;:&quot;snowflake timeout connection parameters&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="snowflake timeout connection parameters" title="snowflake timeout connection parameters" srcset="https://substackcdn.com/image/fetch/$s_!JLwj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 424w, https://substackcdn.com/image/fetch/$s_!JLwj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 848w, https://substackcdn.com/image/fetch/$s_!JLwj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 1272w, https://substackcdn.com/image/fetch/$s_!JLwj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c100fd1-1d90-4a77-b979-68ab265b75ce_1884x408.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Main type of timeouts for snowflake connections</figcaption></figure></div><p>When we hit any of the above timeouts, we can set a <code>backoff_policy</code> to determine how long the connector will back off between connection attempts. <a href="https://github.com/snowflakedb/snowflake-connector-python/blob/5e61c94691c72e6e7e7a7c83849949a188b72172/src/snowflake/connector/backoff_policies.py#L42">The snowflake connector implements linear, exponential and mixed backoff functions</a>, though it is possible to define your own. The default is <code>mixed_backoff()</code>, this is to prevent the issue of the <a href="https://en.wikipedia.org/wiki/Thundering_herd_problem">thundering herd problem</a> where many independent processes may try to perform API calls simultaneously, straining the available API bandwidth.</p><blockquote><h3>&#128161; Warehouse level timeouts impact the snowflake connector too so be mindful of your overal timeout structure.</h3></blockquote><p>Finally, if we want to be able to distinguish in our snowflake logs which application was connected to snowflake through the API, we can use the <code>application</code> attr to add a name of the application (default = "PythonConnector"). This can be useful if we have multiple types of application connecting to snowflake and we want to keep track of connections made through the information schema login table.</p><h2>Cursor</h2><p>Once a connection object is established we can derive a cursor object from it through <code>connection.cursor()</code>. A <code>SnowflakeCursor</code> will handle execution of various SQL commands against a snowflake database, as well as manage the retrieval and storage of the results of those commands.</p><p>As some configurations happen as attributes of the cursor object, some as method choice for execution and some as attributes of execution methods, it makes more sense to consider cursor configuration from the perspective of capabilities.</p><p>In the following sections we will consider how a <code>SnowflakeCursor</code> can be used to read/write data, execute queries synchronously or asynchronously and how we can handle different formats to process queries in a data orchestrator friendly distributive fashion.</p><h1>Synchronous and Asynchronous SQL Statements</h1><p>There&#8217;s generally two ways to handle SQL statement execution with the snowflake API:</p><ol><li><p><strong>Synchronous:</strong> The application will send the query for execution and wait for the results to be available before continuing the program. The results are therefore a python object representation of the results.</p></li><li><p><strong>Asynchronous:</strong> The application will send the query for execution and <strong>NOT</strong> wait for the results. The result is thus a <code>query_id</code> which can be evaluated later to retrieve results.</p></li></ol><p>Generally, you&#8217;d want to use synchronous queries as they are easier to handle and cover most use-cases. To execute synchronously, simply run like:</p><pre><code><code>conn.cursor().execute("CREATE WAREHOUSE IF NOT EXISTS tiny_warehouse_mg")
conn.cursor().execute("CREATE DATABASE IF NOT EXISTS testdb_mg")
conn.cursor().execute("USE DATABASE testdb_mg")
conn.cursor().execute("CREATE SCHEMA IF NOT EXISTS testschema_mg")
</code></code></pre><p>when fetching results for async queries, this requires a little bit more work, your program should determine whether a query is still running and whether it has been successful if finished. Then you can proceed to retrieve results as usual.</p><p>This might look something like:</p><pre><code><code>from snowflake.connector.constants import QueryStatus

# ... process sending initial query...
query_id = conn.cursor.execute_async(cursor_execute_config).sqfid
# ... process receiving query results...
while conn.is_still_running(
    conn.get_query_status_throw_if_error(query_id)
):
    print(conn.get_query_status_throw_if_error(query_id))
    time.sleep(check_interval)
if conn.get_query_status_throw_if_error(query_id) == QueryStatus.SUCCESS:
    resp = cur.get_results_from_sfqid(sfqid=query_id)
    # To work with the results, we need to explicitly fetch them first.
    cur.fetch_arrow_batches()
    print(
        f"Async query completed successfully and cursor ready for fetching. {resp}"
    )
    return cur
else:
    raise ValueError(
        f"Query failed, status is {conn.get_query_status_throw_if_error(query_id)}"
    )

</code></code></pre><p>Note that we are checking the query status consistently until we reach a completed query with either an error or success message. Notice that running <code>fetch_arrow_batches()</code> will store results and their metadata pointers in the cursor object itself.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6kuj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6kuj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 424w, https://substackcdn.com/image/fetch/$s_!6kuj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 848w, https://substackcdn.com/image/fetch/$s_!6kuj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 1272w, https://substackcdn.com/image/fetch/$s_!6kuj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6kuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png" width="1004" height="1224" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1224,&quot;width&quot;:1004,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:217221,&quot;alt&quot;:&quot;sync and async statements for snowflake connector for python&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="sync and async statements for snowflake connector for python" title="sync and async statements for snowflake connector for python" srcset="https://substackcdn.com/image/fetch/$s_!6kuj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 424w, https://substackcdn.com/image/fetch/$s_!6kuj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 848w, https://substackcdn.com/image/fetch/$s_!6kuj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 1272w, https://substackcdn.com/image/fetch/$s_!6kuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc030b6f7-5cf4-457b-8b2c-7142a3cb97f5_1004x1224.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Synchronous versus Asynchronous statements with the snowflake connector for python</figcaption></figure></div><h1>Fetching data with the snowflake cursor</h1><p>Before we get into the separate fetching methods for snowflake cursors, we&#8217;re going to take a deeper look into how the python connector fetches data from snowflake.</p><h2>How snowflake fetches large datasets</h2><p>When working with Snowflake, it's important to understand the mechanisms behind data fetching, especially for large datasets. Depending on the configuration, the API employs different processes to fetch data:</p><ul><li><p><strong>Small Datasets:</strong> The API can prefetch the entire response and load it directly into a Python object in memory. This is efficient and quick, making it ideal for smaller datasets.</p></li><li><p><strong>Large Datasets:</strong> For larger datasets, the API can be configured to use a chunking method. Initially, a chunk of data is prefetched into memory, similar to the process for smaller datasets. Subsequently, the API fetches metadata pointers to the next chunks of data. This process is structured like a chain, with each chunk containing a pointer to the next chunk's location.</p></li></ul><p>Note that the prefetch response and chunk responses are returned from different URLs. The prefetch response is returned directly by the SQL endpoint the connector interacts with <code>https://&lt;account_identifier*&gt;*.snowflakecomputing.com/api</code> . The chunking responses will return <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html">pre-signed S3 urls</a> with a default lease of 6 hours.</p><p>What happens under the hood is that snowflake has S3 resources specifically dedicated to your account/service user that you use to set up initial S3 connections with. Snowflake will provide you with chunks/partitions of your data through S3 through <code>S3-presigned-urls</code> using your service account id. These links are of a shape similar to:</p><p><code>https://sfc-&lt;server&gt;-&lt;data-center&gt;-customer-stage.s3.&lt;aws-cloud-region&gt;/&lt;service account id&gt;/results/&lt;statement_id&gt;/main/data_&lt;chunk_id&gt;?&lt;aws-s3-presigned-url-details&gt;</code></p><p>Please do note that from a security perspective, these links also need to be permitted by any VPN/proxy you might be using and you must be very careful about logging these links as <strong>ANY</strong> outside party can use these links to access the chunk data within the lease time.</p><p>The following is a visual representation of what happens under the hood:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Zix8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Zix8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 424w, https://substackcdn.com/image/fetch/$s_!Zix8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 848w, https://substackcdn.com/image/fetch/$s_!Zix8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 1272w, https://substackcdn.com/image/fetch/$s_!Zix8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Zix8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png" width="1456" height="1071" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/efae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1071,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:451574,&quot;alt&quot;:&quot;how snowflake handles providing large query results.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="how snowflake handles providing large query results." title="how snowflake handles providing large query results." srcset="https://substackcdn.com/image/fetch/$s_!Zix8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 424w, https://substackcdn.com/image/fetch/$s_!Zix8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 848w, https://substackcdn.com/image/fetch/$s_!Zix8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 1272w, https://substackcdn.com/image/fetch/$s_!Zix8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefae6576-7835-4cd9-a34b-1b84f0200a1d_2112x1554.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">How snowflake handles providing large query results with an S3 backend setup.</figcaption></figure></div><p>Essentially, when snowflake processes your query, it will store the results into chunks in S3 and the iterator objects within the snowflake connection objects will essentially just download each chunk through a pre-signed s3 url into an object in memory of your choice.</p><h2>Internal python data types for cursor results</h2><h2>Single process fetching methods</h2><p>With this type of method of form <code>cursor.fetch_&lt;type&gt;()</code> , the snowflake cursor is able to fetch data from a synchronous or asynchronous query into several formats into a single process. Depending on the size of the data and program complexity there are several possible methods.</p><h3>Fetchall</h3><p><code>cur.fetchall()</code> is the most straightforward fetching method. When a statement result is fetched with this function, a list of tuples is generated where each tuple element corresponds to a column in the result set. For example:</p><pre><code><code># command
cmd = """
select *
From  (values ('Dummy1')
            ,('Dummy2')
    ) A(Dummies)
"""

cursor.execute(cmd)
results = cursor.fetchall()

# results
results: [
        (
            'Dummy1',
        ),
        (
            'Dummy2',
        ),
    ] (list) len=2
</code></code></pre><p>Be careful however, this method will load all of the data directly into memory. This method is NOT advised to run for queries where large result sets are expected. This method can be quite useful when running sql statements that can have variable outcomes such as Data Control Language (DCL) statements.</p><h3>Fetchone</h3><p><code>cur.fetchone()</code> is similar to the <code>fetchall()</code> method, but instead of fetching all the data into a list of tuples at once, it will fetch one record at a time. Running the same statement as above, we get:</p><pre><code><code>results: (
    'Dummy1',
) (tuple) len=1
</code></code></pre><h3>Fetchmany</h3><p><code>cur.fetchmany()</code> is similar to <code>cur.fetchone()</code> , but it returns <code>n</code>rows of data from the query result set. This can be useful for testing smaller subsets of the data before proceeding with the application code.</p><h3>Fetch_arrow_all</h3><p><code>cur.fetch_arrow_all()</code> will prefetch the first chunk(s) of results into the cursor and provide a generator for fetching the metadata references to the proceeding arrow chunks. Again, do note that a fetch function using <code>all</code> will directly load everything into memory:</p><pre><code><code>total_rows = 10000
cmd = """
select *
From  (values
"""
for i in range(total_rows):
    cmd += f"('Dummy{i}')"
    if i &lt; total_rows-1:
        cmd += ",\\n"
    else:
        cmd += "\\n"
cmd += ") A(Dummies)"

cursor.execute(cmd)
results = cursor.fetch_arrow_all()

# results
results: (
    pyarrow.Table
    DUMMIES: string not null
    ----
    DUMMIES:
    [["Dummy0","Dummy1","Dummy2","Dummy3","Dummy4",...,"Dummy9995","Dummy9996","Dummy9997","Dummy9998","Dummy9999"]]
) (Table) len=10000
</code></code></pre><p>This method is useful if your application can handle arrow format well. The arrow object is also pretty memory efficient, the above result object is &#177;14 kb large.</p><h3>FetchArrowBatches</h3><p>Chances are, you sometimes have to query datasets that will be many times larger than the example above. If these datasets exceed the size of your memory allocation to the process, this will not suffice. For these situations, there is a set of fetching methods that use batches to retrieve data from a snowflake query.</p><p>let&#8217;s say we generate a much larger dataset of 10.000 rows by 100 columns</p><pre><code><code>  # Define the number of rows and columns
  total_rows = 10000
  total_columns = 100

  # Start building the SQL command
  cmd = "SELECT * FROM (VALUES\\n"

  # Iterate to create rows
  for i in range(total_rows):
      # Generate values for each column
      values = ", ".join(f"'Dummy{i}_{j}'" for j in range(total_columns))
      cmd += f"({values})"
      if i &lt; total_rows - 1:
          cmd += ",\\n"
      else:
          cmd += "\\n"

  # Finish the SQL command
  cmd += ") A(" + ", ".join(f"Col{j}" for j in range(total_columns)) + ")"

</code></code></pre><p>when we now fetch with <code>cur.fetch_arrow_batches()</code> this will produce a python generator which will produce 6 chunks of arrow tables:</p><pre><code><code>cursor.execute(cmd)
results = cursor.fetch_arrow_batches()

# results
counter=0
for batch in results:
    counter+=1
    print(counter)
# results
1
2
3
4
5
6
</code></code></pre><p>where each chunk will match the format of the <code>arrow_fetch_all</code> tables.</p><p>An important thing to note is that these generators cannot be easily passed around to other processes or tasks which has implications for data orchestration tooling. While it is possible to compute each chunk through a for loop and submit it to separate tasks in your orchestrator, this is rather inefficient because you are passing around large amounts of data into inputs of your downstream tasks. For that purpose, there are <code>ResultBatches</code> which are described in a later section.</p><h3>FetchPandasAll and FetchPandasBatches</h3><p>The snowflake connector also support fetching and converting data into pandas dataframes. Running the same code as above, but for a table of 5x5, we get the following format of our results:</p><pre><code><code>    results: &lt;DataFrame({
        'COL0': &lt;Series({
            0: 'Dummy0_0',
            1: 'Dummy1_0',
            2: 'Dummy2_0',
            3: 'Dummy3_0',
            4: 'Dummy4_0',
        })&gt;,
        'COL1': &lt;Series({
            0: 'Dummy0_1',
            1: 'Dummy1_1',
            2: 'Dummy2_1',
            3: 'Dummy3_1',
            4: 'Dummy4_1',
        })&gt;,
        'COL2': &lt;Series({
            0: 'Dummy0_2',
            1: 'Dummy1_2',
            2: 'Dummy2_2',
            3: 'Dummy3_2',
            4: 'Dummy4_2',
        })&gt;,
        'COL3': &lt;Series({
            0: 'Dummy0_3',
            1: 'Dummy1_3',
            2: 'Dummy2_3',
            3: 'Dummy3_3',
            4: 'Dummy4_3',
        })&gt;,
        'COL4': &lt;Series({
            0: 'Dummy0_4',
            1: 'Dummy1_4',
            2: 'Dummy2_4',
            3: 'Dummy3_4',
            4: 'Dummy4_4',
        })&gt;,
    })&gt; (DataFrame) len=5
</code></code></pre><p>The benefit of pandas dataframes is obvious to any data professional that has been working with data and python: it is much easier to do transformations. Pandas has an extensive API for doing so. The downside is a larger memory footprint, but. Similarly to <code>fetch_arrow_batches()</code>, we can perform <code>fetch_pandas_batches()</code> to produce a generator of pandas dataframes to work with.</p><h2>Multi-process fetching: ResultBatches</h2><p>A common situation when handling large amounts of data from a database is distributing the transformation workload across several worker nodes in a data orchestrator like airflow or big data frameworks like Spark.</p><p>The earlier fetching methods work fine when working with a single process but they don&#8217;t cover this use case very well.</p><p>When we want to integrate with systems like these, snowflake provides a convenient result format called a <code>ResultBatch</code> which we can access through the method <code>fetch_result_batches()</code>. Unlike our generators which are difficult to pass around in frameworks heavily utilizing python futures like prefect or there&#8217;s limited bandwith, these chunks can be serialized with a <code>pickle.dump</code> into a small efficient binary representation (think deca kilobytes). This binary sequence can be passed around in most data orchestrators just fine.</p><p>When this data structure is deserialized in a target process, it can be deserialized into any of the other representations. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!me_M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!me_M!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 424w, https://substackcdn.com/image/fetch/$s_!me_M!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 848w, https://substackcdn.com/image/fetch/$s_!me_M!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 1272w, https://substackcdn.com/image/fetch/$s_!me_M!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!me_M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png" width="1456" height="1512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1512,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:349178,&quot;alt&quot;:&quot;Summary of primary sql statement result fetching methods in the snowflake connector for python&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Summary of primary sql statement result fetching methods in the snowflake connector for python" title="Summary of primary sql statement result fetching methods in the snowflake connector for python" srcset="https://substackcdn.com/image/fetch/$s_!me_M!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 424w, https://substackcdn.com/image/fetch/$s_!me_M!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 848w, https://substackcdn.com/image/fetch/$s_!me_M!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 1272w, https://substackcdn.com/image/fetch/$s_!me_M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f17a81c-2e4f-4f84-ae2d-58779b28c574_1458x1514.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Summary of primary sql statement result fetching methods in the snowflake connector for python</figcaption></figure></div><h1>Loading data into snowflake through python connector</h1><p>There is many ways to load data into snowflake but for the purposes of this article I will only briefly describe the three main methods when using the snowflake connector for python (I can follow up in a subsequent article):</p><ol><li><p>It&#8217;s possible to do a standard cycle of loading data into S3, connecting this to a snowflake stage and then issuing copy into command through the cursor.</p></li><li><p><code>execute_cursor()</code> can be extended with a parameter <code>filestream</code> to push a python <code>IO</code> object directly to a snowflake table. This is useful for larger-than-memory, non-dataframe objects.</p></li><li><p>The snowflake connector library also has a submodule called pandas_tools which contains a function called <code>write_pandas()</code>. This can used to write a pandas dataframe directly to snowflake. It auto-generates and runs statements you would typically run to implement the first way.</p></li></ol><h1>Wrapping up</h1><p>Navigating the Snowflake ecosystem as a data engineer opens up a world of possibilities for building robust data applications and integrating powerful third-party tools. At the heart of this ecosystem is the Snowflake Python connector, a versatile tool that enables secure, efficient, and flexible interaction with Snowflake's data platform.</p><p>If you found this article helpful or insightful and/or are interested in more, please sign up to this substack below!<br></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Data code model part II: Python Typing]]></title><description><![CDATA[Using python type constructs to structure your python code.]]></description><link>https://www.blog.zelytics.tech/p/data-code-model-part-ii-python-typing</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/data-code-model-part-ii-python-typing</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Wed, 22 May 2024 07:51:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QU3K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QU3K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QU3K!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!QU3K!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!QU3K!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!QU3K!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QU3K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:591222,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QU3K!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!QU3K!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!QU3K!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!QU3K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5072399-9f82-4a99-bbc2-05b0ab47482d_1792x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is part 2 of a series on data code modelling for data engineering. In part 1, we went over abstract base classes in python and how these can be used to design software contracts between python classes:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f25af54c-2fcf-443f-92fe-1bbd49df2f0d&quot;,&quot;caption&quot;:&quot;When working in data engineering, you will often have to work with python code bases to manage all sorts of processes in your data stack from ETL, to orchestration, to infrastructure management, to observability and much more. One view of data engineering is that of a blend of software engineering and data science. Oftentimes as data engineers, we will &#8230;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Data Code Modelling: Abstract Base Classes&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:143274682,&quot;name&quot;:&quot;Tony Zeljkovic&quot;,&quot;bio&quot;:&quot;Writing about data engineering.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/41c64ca2-28fc-43a6-b0bb-404fce469336.avif&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-04-28T08:54:06.567Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://tonyzeljkovic.substack.com/p/data-code-modelling-abstract-base&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:144028045,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Tony&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe06bfb94-797e-445f-ba0b-8117553a9aa7_800x800.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>In this article, we will go over python typing. A good type system design is the foundation of a robust code base. Python is extensively typed and has extensive support for generating custom types and using these types at various locations throughout the code through the <a href="https://github.com/python/cpython/tree/3.12/Lib/typing.py">Typing</a> library.</p><blockquote><p>&#128161; Python typing is an EXTENSIVE topic. Therefore, this article will only cover some essentials on this topic.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gmEv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gmEv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 424w, https://substackcdn.com/image/fetch/$s_!gmEv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 848w, https://substackcdn.com/image/fetch/$s_!gmEv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 1272w, https://substackcdn.com/image/fetch/$s_!gmEv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gmEv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png" width="1456" height="1684" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1684,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:353737,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gmEv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 424w, https://substackcdn.com/image/fetch/$s_!gmEv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 848w, https://substackcdn.com/image/fetch/$s_!gmEv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 1272w, https://substackcdn.com/image/fetch/$s_!gmEv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c86b59-1134-444d-9ff2-cc646dbec5d6_1942x2246.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h1>Why care about python types</h1><p>There are a few main reasons why it pays dividends to lay out your python typing more carefully:</p><ol><li><p>Types are an efficient expression of function. It is a lot easier to read and write code with proper typing annotation than dealing with tons of documentation.</p></li><li><p>Types can be used by static code analysers like <a href="https://mypy.readthedocs.io/en/stable/getting_started.html">mypy</a> to provide insights on potential code issues <strong>BEFORE</strong> it is run.</p></li><li><p>Types can be used by python libraries to enforce specific class behavior. For example, <a href="https://docs.python.org/3/library/dataclasses.html">dataclasses</a> and <a href="https://docs.pydantic.dev/latest/">pydantic</a> can be used to create a data model class which uses types to enforce specific outputs (more on that in part 3).</p></li></ol><h1>Python type hints</h1><p>A type hint is a annotation of sorts that can be added to python code to signify the types of various types of objects and attributes. Type hinting can be done at a few important locations in your code:</p><ul><li><p>Class attributes</p></li><li><p>Function arguments</p></li><li><p>Function outputs</p></li><li><p>Variables</p></li></ul><p>To illustrate this, view the example below:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130380432\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-type_hint_example-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;type_hint_example.py\&quot;>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DataFrame</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>name</span>: <span class=pl-s1>str</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>rows</span>: <span class=pl-s1>int</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__init__</span>(<span class=pl-s1>self</span>, <span class=pl-s1>name</span>: <span class=pl-s1>str</span>, <span class=pl-s1>rows</span>: <span class=pl-s1>int</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>name</span> <span class=pl-c1>=</span> <span class=pl-s1>name</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>rows</span> <span class=pl-c1>=</span> <span class=pl-s1>rows</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>process_dataframe</span>(<span class=pl-s1>df</span>: <span class=pl-v>DataFrame</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Processing <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>df</span>.<span class=pl-s1>name</span><span class=pl-kos>}</span></span> with <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>df</span>.<span class=pl-s1>rows</span><span class=pl-kos>}</span></span> rows.&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>df_name</span>: <span class=pl-s1>str</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;user_data&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>df_rows</span>: <span class=pl-s1>int</span> <span class=pl-c1>=</span> <span class=pl-c1>1000000</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>df</span>: <span class=pl-v>DataFrame</span> <span class=pl-c1>=</span> <span class=pl-v>DataFrame</span>(<span class=pl-s1>df_name</span>, <span class=pl-s1>df_rows</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type_hint_example-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-type_hint_example-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>result</span>: <span class=pl-s1>str</span> <span class=pl-c1>=</span> <span class=pl-en>process_dataframe</span>(<span class=pl-s1>df</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/fe20bcec465a6105d12a27942db87f04/raw/e28ac2de53ee95c765ab88b098d07d2603c84a97/type_hint_example.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/fe20bcec465a6105d12a27942db87f04#file-type_hint_example-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          type_hint_example.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130380432" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-type_hint_example-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="type_hint_example.py">
        <tbody><tr>
          <td id="file-type_hint_example-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-type_hint_example-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DataFrame</span>:</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-type_hint_example-py-LC2" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">name</span>: <span class="pl-s1">str</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-type_hint_example-py-LC3" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">rows</span>: <span class="pl-s1">int</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-type_hint_example-py-LC4" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-type_hint_example-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">name</span>: <span class="pl-s1">str</span>, <span class="pl-s1">rows</span>: <span class="pl-s1">int</span>):</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-type_hint_example-py-LC6" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">name</span> <span class="pl-c1">=</span> <span class="pl-s1">name</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-type_hint_example-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">rows</span> <span class="pl-c1">=</span> <span class="pl-s1">rows</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-type_hint_example-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-type_hint_example-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">process_dataframe</span>(<span class="pl-s1">df</span>: <span class="pl-v">DataFrame</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-type_hint_example-py-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-s">f"Processing <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">df</span>.<span class="pl-s1">name</span><span class="pl-kos">}</span></span> with <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">df</span>.<span class="pl-s1">rows</span><span class="pl-kos">}</span></span> rows."</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-type_hint_example-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-type_hint_example-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">df_name</span>: <span class="pl-s1">str</span> <span class="pl-c1">=</span> <span class="pl-s">"user_data"</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-type_hint_example-py-LC13" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">df_rows</span>: <span class="pl-s1">int</span> <span class="pl-c1">=</span> <span class="pl-c1">1000000</span></td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-type_hint_example-py-LC14" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">df</span>: <span class="pl-v">DataFrame</span> <span class="pl-c1">=</span> <span class="pl-v">DataFrame</span>(<span class="pl-s1">df_name</span>, <span class="pl-s1">df_rows</span>)</td>
        </tr>
        <tr>
          <td id="file-type_hint_example-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-type_hint_example-py-LC15" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">result</span>: <span class="pl-s1">str</span> <span class="pl-c1">=</span> <span class="pl-en">process_dataframe</span>(<span class="pl-s1">df</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/fe20bcec465a6105d12a27942db87f04/raw/e28ac2de53ee95c765ab88b098d07d2603c84a97/type_hint_example.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/fe20bcec465a6105d12a27942db87f04#file-type_hint_example-py" class="Link--inTextBlock">
          type_hint_example.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>You will notice we are using the type constructs <strong>str</strong>, <strong>int</strong><code> </code>and the custom class <strong>DataFrame</strong> at several places in our code. This shows a powerful feature of typing: <strong>All python data types and user generated custom objects can be used as a type hint.</strong></p><p>This means that it&#8217;s also possible to use constructs from third party libraries such as pandas or numpys as a type hint. Thus, a type hint like <strong>df: pd.DataFrame</strong> is completely acceptable!</p><p>Why does this work? Python type hints do <strong>NOT </strong>impact your python code during runtime. They can be used by other libraries to create additional behavior, but in the &#8220;vanilla&#8221; implementation, they don&#8217;t impact how your code runs which is intended by design.</p><h1>Generic types</h1><p>A subset of python types are called the <strong>generic types</strong>. A generic type is characterised by a syntax like <strong>type[&#8230;]</strong> where <strong>&#8230; </strong>can be any other type. This is generally reserved for types that can be constructed as supersets of other types. For example, let&#8217;s say we have a list of integers in python, this could be type hinted like <strong>list[int] . </strong>This is pretty powerful as it allows us to have a more precise definition of this these sorts of types in our code. This can get infinitely complex too so <strong>list[list[list[str]]] </strong>is also an acceptable type hint. </p><p>Usually it&#8217;s rather obvious a type is a generic type. For example, for collections like <strong>list</strong>, <strong>dict</strong> or <strong>set</strong> it makes sense they are generics. As of current writing, it is not yet possible to determine if a type is generic simply by checking the base type (like <strong>list) </strong>but it is possible to confirm a generic once it&#8217;s parameterised (e.g <strong>list[int] ). </strong>Generally this can be confirmed like so:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130380716\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-is_generic-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;is_generic.py\&quot;>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-s1>get_origin</span>, <span class=pl-s1>get_args</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Define some generic and non-generic types</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>generic_type</span> <span class=pl-c1>=</span> <span class=pl-s1>list</span>[<span class=pl-s1>int</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>non_generic_type</span> <span class=pl-c1>=</span> <span class=pl-s1>int</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>generic_type_without_params</span> <span class=pl-c1>=</span> <span class=pl-s1>list</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Function to check if a type is a generic type</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>is_generic_type</span>(<span class=pl-s1>tp</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-en>get_origin</span>(<span class=pl-s1>tp</span>) <span class=pl-c1>is</span> <span class=pl-c1>not</span> <span class=pl-c1>None</span> <span class=pl-c1>or</span> <span class=pl-en>hasattr</span>(<span class=pl-s1>tp</span>, <span class=pl-s>&amp;#39;__origin__&amp;#39;</span>) <span class=pl-c1>and</span> <span class=pl-s1>tp</span>.<span class=pl-s1>__origin__</span> <span class=pl-c1>is</span> <span class=pl-c1>not</span> <span class=pl-c1>None</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Function to check if a type is a parameterized generic type</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>is_parameterized_generic_type</span>(<span class=pl-s1>tp</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-en>get_origin</span>(<span class=pl-s1>tp</span>) <span class=pl-c1>is</span> <span class=pl-c1>not</span> <span class=pl-c1>None</span> <span class=pl-c1>and</span> <span class=pl-en>len</span>(<span class=pl-en>get_args</span>(<span class=pl-s1>tp</span>)) <span class=pl-c1>&amp;gt;</span> <span class=pl-c1>0</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>if</span> <span class=pl-s1>__name__</span> <span class=pl-c1>==</span> <span class=pl-s>&amp;quot;__main__&amp;quot;</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;#39;Is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>generic_type</span><span class=pl-kos>}</span></span> a generic type? <span class=pl-s1><span class=pl-kos>{</span><span class=pl-en>is_generic_type</span>(<span class=pl-s1>generic_type</span>)<span class=pl-kos>}</span></span>&amp;#39;</span>)  <span class=pl-c># True</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;#39;Is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>non_generic_type</span><span class=pl-kos>}</span></span> a generic type? <span class=pl-s1><span class=pl-kos>{</span><span class=pl-en>is_generic_type</span>(<span class=pl-s1>non_generic_type</span>)<span class=pl-kos>}</span></span>&amp;#39;</span>)  <span class=pl-c># False</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;#39;Is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>generic_type_without_params</span><span class=pl-kos>}</span></span> a generic type? <span class=pl-s1><span class=pl-kos>{</span><span class=pl-en>is_generic_type</span>(<span class=pl-s1>generic_type_without_params</span>)<span class=pl-kos>}</span></span>&amp;#39;</span>)  <span class=pl-c># True</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;#39;Is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>generic_type</span><span class=pl-kos>}</span></span> a parameterized generic type? <span class=pl-s1><span class=pl-kos>{</span><span class=pl-en>is_parameterized_generic_type</span>(<span class=pl-s1>generic_type</span>)<span class=pl-kos>}</span></span>&amp;#39;</span>)  <span class=pl-c># True</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-is_generic-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-is_generic-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;#39;Is <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>generic_type_without_params</span><span class=pl-kos>}</span></span> a parameterized generic type? <span class=pl-s1><span class=pl-kos>{</span><span class=pl-en>is_parameterized_generic_type</span>(<span class=pl-s1>generic_type_without_params</span>)<span class=pl-kos>}</span></span>&amp;#39;</span>)  <span class=pl-c># False</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/b90c6e030c00ccfafdb69d83ba68859e/raw/9247a8e876097670a9012b3c8d5680985c4e2c66/is_generic.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/b90c6e030c00ccfafdb69d83ba68859e#file-is_generic-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          is_generic.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130380716" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-is_generic-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="is_generic.py">
        <tbody><tr>
          <td id="file-is_generic-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-is_generic-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-s1">get_origin</span>, <span class="pl-s1">get_args</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-is_generic-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-is_generic-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Define some generic and non-generic types</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-is_generic-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">generic_type</span> <span class="pl-c1">=</span> <span class="pl-s1">list</span>[<span class="pl-s1">int</span>]</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-is_generic-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">non_generic_type</span> <span class="pl-c1">=</span> <span class="pl-s1">int</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-is_generic-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">generic_type_without_params</span> <span class="pl-c1">=</span> <span class="pl-s1">list</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-is_generic-py-LC7" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-is_generic-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Function to check if a type is a generic type</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-is_generic-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">is_generic_type</span>(<span class="pl-s1">tp</span>):</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-is_generic-py-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-en">get_origin</span>(<span class="pl-s1">tp</span>) <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-c1">None</span> <span class="pl-c1">or</span> <span class="pl-en">hasattr</span>(<span class="pl-s1">tp</span>, <span class="pl-s">'__origin__'</span>) <span class="pl-c1">and</span> <span class="pl-s1">tp</span>.<span class="pl-s1">__origin__</span> <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-c1">None</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-is_generic-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-is_generic-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Function to check if a type is a parameterized generic type</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-is_generic-py-LC13" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">is_parameterized_generic_type</span>(<span class="pl-s1">tp</span>):</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-is_generic-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-en">get_origin</span>(<span class="pl-s1">tp</span>) <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-c1">None</span> <span class="pl-c1">and</span> <span class="pl-en">len</span>(<span class="pl-en">get_args</span>(<span class="pl-s1">tp</span>)) <span class="pl-c1">&gt;</span> <span class="pl-c1">0</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-is_generic-py-LC15" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-is_generic-py-LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:</td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-is_generic-py-LC17" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f'Is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">generic_type</span><span class="pl-kos">}</span></span> a generic type? <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">is_generic_type</span>(<span class="pl-s1">generic_type</span>)<span class="pl-kos">}</span></span>'</span>)  <span class="pl-c"># True</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-is_generic-py-LC18" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f'Is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">non_generic_type</span><span class="pl-kos">}</span></span> a generic type? <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">is_generic_type</span>(<span class="pl-s1">non_generic_type</span>)<span class="pl-kos">}</span></span>'</span>)  <span class="pl-c"># False</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-is_generic-py-LC19" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f'Is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">generic_type_without_params</span><span class="pl-kos">}</span></span> a generic type? <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">is_generic_type</span>(<span class="pl-s1">generic_type_without_params</span>)<span class="pl-kos">}</span></span>'</span>)  <span class="pl-c"># True</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-is_generic-py-LC20" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f'Is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">generic_type</span><span class="pl-kos">}</span></span> a parameterized generic type? <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">is_parameterized_generic_type</span>(<span class="pl-s1">generic_type</span>)<span class="pl-kos">}</span></span>'</span>)  <span class="pl-c"># True</span></td>
        </tr>
        <tr>
          <td id="file-is_generic-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-is_generic-py-LC21" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f'Is <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">generic_type_without_params</span><span class="pl-kos">}</span></span> a parameterized generic type? <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">is_parameterized_generic_type</span>(<span class="pl-s1">generic_type_without_params</span>)<span class="pl-kos">}</span></span>'</span>)  <span class="pl-c"># False</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/b90c6e030c00ccfafdb69d83ba68859e/raw/9247a8e876097670a9012b3c8d5680985c4e2c66/is_generic.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/b90c6e030c00ccfafdb69d83ba68859e#file-is_generic-py" class="Link--inTextBlock">
          is_generic.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>This is all just to show that, although generics are widely used, they don&#8217;t generally inherit from a single hierarchy, they&#8217;re rather objects with related implementations.</p><p>There are a bunch of generic types defined in various python standard libraries that help a user implement and understand these types correctly. A non exhaustive list is provided below:</p><p><strong><a href="https://docs.python.org/3/library/typing.html">Typing</a></strong></p><ul><li><p><a href="https://docs.python.org/3/library/stdtypes.html#tuple">tuple</a></p></li><li><p><a href="https://docs.python.org/3/library/stdtypes.html#list">list</a></p></li><li><p><a href="https://docs.python.org/3/library/stdtypes.html#dict">dict</a></p></li><li><p><a href="https://docs.python.org/3/library/stdtypes.html#set">set</a></p></li></ul><p><strong><a href="https://docs.python.org/3/library/collections.html">Collections</a></strong></p><ul><li><p><a href="https://docs.python.org/3/library/collections.html#collections.deque">collections.deque</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.html#collections.defaultdict">collections.defaultdict</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.html#collections.OrderedDict">collections.OrderedDict</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.html#collections.Counter">collections.Counter</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.html#collections.ChainMap">collections.ChainMap</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Awaitable">collections.abc.Awaitable</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Coroutine">collections.abc.Coroutine</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.AsyncIterable">collections.abc.AsyncIterable</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.AsyncIterator">collections.abc.AsyncIterator</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.AsyncGenerator">collections.abc.AsyncGenerator</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable">collections.abc.Iterable</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator">collections.abc.Iterator</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Generator">collections.abc.Generator</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Reversible">collections.abc.Reversible</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Container">collections.abc.Container</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Collection">collections.abc.Collection</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable">collections.abc.Callable</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Set">collections.abc.Set</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSet">collections.abc.MutableSet</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping">collections.abc.Mapping</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping">collections.abc.MutableMapping</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence">collections.abc.Sequence</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSequence">collections.abc.MutableSequence</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.ByteString">collections.abc.ByteString</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.MappingView">collections.abc.MappingView</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.KeysView">collections.abc.KeysView</a></p></li><li><p><a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.ItemsView">collections.abc.ItemsView</a></p></li></ul><p><strong><a href="https://docs.python.org/3/library/contextlib.html">Contextlib</a></strong></p><ul><li><p><a href="https://docs.python.org/3/library/contextlib.html#contextlib.AbstractContextManager">contextlib.AbstractContextManager</a></p></li><li><p><a href="https://docs.python.org/3/library/contextlib.html#contextlib.AbstractAsyncContextManager">contextlib.AbstractAsyncContextManager</a></p></li></ul><p><strong><a href="https://docs.python.org/3/library/queue.html">Queue</a></strong></p><ul><li><p><a href="https://docs.python.org/3/library/queue.html#queue.LifoQueue">queue.LifoQueue</a></p></li><li><p><a href="https://docs.python.org/3/library/queue.html#queue.Queue">queue.Queue</a></p></li><li><p><a href="https://docs.python.org/3/library/queue.html#queue.PriorityQueue">queue.PriorityQueue</a></p></li><li><p><a href="https://docs.python.org/3/library/queue.html#queue.SimpleQueue">queue.SimpleQueue</a></p></li></ul><p><strong><a href="https://docs.python.org/3/library/re.html">Re</a></strong></p><ul><li><p><a href="https://docs.python.org/3/library/re.html#re-objects">re.Pattern</a></p></li><li><p><a href="https://docs.python.org/3/library/re.html#match-objects">re.Match</a></p></li></ul><p><strong>Others</strong></p><ul><li><p><a href="https://docs.python.org/3/library/dataclasses.html#dataclasses.Field">dataclasses.Field</a></p></li><li><p><a href="https://docs.python.org/3/library/functools.html#functools.cached_property">functools.cached_property</a></p></li><li><p><a href="https://docs.python.org/3/library/functools.html#functools.partialmethod">functools.partialmethod</a></p></li><li><p><a href="https://docs.python.org/3/library/os.html#os.PathLike">os.PathLike</a></p></li><li><p><a href="https://docs.python.org/3/library/shelve.html#shelve.BsdDbShelf">shelve.BsdDbShelf</a></p></li><li><p><a href="https://docs.python.org/3/library/shelve.html#shelve.DbfilenameShelf">shelve.DbfilenameShelf</a></p></li><li><p><a href="https://docs.python.org/3/library/shelve.html#shelve.Shelf">shelve.Shelf</a></p></li><li><p><a href="https://docs.python.org/3/library/types.html#types.MappingProxyType">types.MappingProxyType</a></p></li><li><p><a href="https://docs.python.org/3/library/weakref.html#weakref.WeakKeyDictionary">weakref.WeakKeyDictionary</a></p></li><li><p><a href="https://docs.python.org/3/library/weakref.html#weakref.WeakMethod">weakref.WeakMethod</a></p></li><li><p><a href="https://docs.python.org/3/library/weakref.html#weakref.WeakSet">weakref.WeakSet</a></p></li><li><p><a href="https://docs.python.org/3/library/weakref.html#weakref.WeakValueDictionary">weakref.WeakValueDictionary</a></p></li></ul><h1>Annotated types</h1><p>An annotated type can be seen as a custom type definition in python. It&#8217;s possible to define a type and associate some metadata with it. Generally, the metadata from these annotated types can be used to add additional instructions for validation of data. We will get back to leveraging that when we get into <strong>pydantic</strong> , but for now, just know you can define an annotated type like so:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381016\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-annotated_type-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;annotated_type.py\&quot;>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>Annotated</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing_extensions</span> <span class=pl-k>import</span> <span class=pl-v>Annotated</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Define an annotated type with metadata</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-v>Age</span> <span class=pl-c1>=</span> <span class=pl-v>Annotated</span>[<span class=pl-s1>int</span>, <span class=pl-s>&amp;quot;Must be a non-negative integer&amp;quot;</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>check_age</span>(<span class=pl-s1>age</span>: <span class=pl-v>Age</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>if</span> <span class=pl-s1>age</span> <span class=pl-c1>&amp;lt;</span> <span class=pl-c1>0</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>raise</span> <span class=pl-v>ValueError</span>(<span class=pl-s>&amp;quot;Age must be a non-negative integer&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;Age is valid: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>age</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage examples</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>try</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>check_age</span>(<span class=pl-c1>25</span>)  <span class=pl-c># Valid</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>check_age</span>(<span class=pl-c1>-</span><span class=pl-c1>5</span>)  <span class=pl-c># Invalid, will raise ValueError</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>except</span> <span class=pl-v>ValueError</span> <span class=pl-k>as</span> <span class=pl-s1>e</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-annotated_type-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-annotated_type-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>e</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/7ac91966bbabf88e36384e7a04c8e20d/raw/14208b1672340669cca712e1daefd9123c06669a/annotated_type.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/7ac91966bbabf88e36384e7a04c8e20d#file-annotated_type-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          annotated_type.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381016" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-annotated_type-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="annotated_type.py">
        <tbody><tr>
          <td id="file-annotated_type-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-annotated_type-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Annotated</span></td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-annotated_type-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing_extensions</span> <span class="pl-k">import</span> <span class="pl-v">Annotated</span></td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-annotated_type-py-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-annotated_type-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Define an annotated type with metadata</span></td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-annotated_type-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-v">Age</span> <span class="pl-c1">=</span> <span class="pl-v">Annotated</span>[<span class="pl-s1">int</span>, <span class="pl-s">"Must be a non-negative integer"</span>]</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-annotated_type-py-LC6" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-annotated_type-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">check_age</span>(<span class="pl-s1">age</span>: <span class="pl-v">Age</span>):</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-annotated_type-py-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">if</span> <span class="pl-s1">age</span> <span class="pl-c1">&lt;</span> <span class="pl-c1">0</span>:</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-annotated_type-py-LC9" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">raise</span> <span class="pl-v">ValueError</span>(<span class="pl-s">"Age must be a non-negative integer"</span>)</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-annotated_type-py-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f"Age is valid: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">age</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-annotated_type-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-annotated_type-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage examples</span></td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-annotated_type-py-LC13" class="blob-code blob-code-inner js-file-line"><span class="pl-k">try</span>:</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-annotated_type-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">check_age</span>(<span class="pl-c1">25</span>)  <span class="pl-c"># Valid</span></td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-annotated_type-py-LC15" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">check_age</span>(<span class="pl-c1">-</span><span class="pl-c1">5</span>)  <span class="pl-c"># Invalid, will raise ValueError</span></td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-annotated_type-py-LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-k">except</span> <span class="pl-v">ValueError</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:</td>
        </tr>
        <tr>
          <td id="file-annotated_type-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-annotated_type-py-LC17" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">e</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/7ac91966bbabf88e36384e7a04c8e20d/raw/14208b1672340669cca712e1daefd9123c06669a/annotated_type.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/7ac91966bbabf88e36384e7a04c8e20d#file-annotated_type-py" class="Link--inTextBlock">
          annotated_type.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>Functions or other callable objects can be annotated using <strong>collections.abc.Callable</strong> or <strong>typing.Callable</strong>. For example, <strong>Callable[[int], str]</strong> indicates a function that takes an <strong>int</strong> and returns a <strong>str</strong>. An example is:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381069\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-callable_annotation-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;callable_annotation.py\&quot;>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>collections</span>.<span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>Callable</span>, <span class=pl-v>Awaitable</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Function with callable parameter</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>feeder</span>(<span class=pl-s1>get_next_item</span>: <span class=pl-v>Callable</span>[[], <span class=pl-s1>str</span>]) <span class=pl-c1>-&amp;gt;</span> <span class=pl-c1>None</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    ...  <span class=pl-c># Body</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Function with multiple callable parameters</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>async_query</span>(<span class=pl-s1>on_success</span>: <span class=pl-v>Callable</span>[[<span class=pl-s1>int</span>], <span class=pl-c1>None</span>],</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-s1>on_error</span>: <span class=pl-v>Callable</span>[[<span class=pl-s1>int</span>, <span class=pl-v>Exception</span>], <span class=pl-c1>None</span>]) <span class=pl-c1>-&amp;gt;</span> <span class=pl-c1>None</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    ...  <span class=pl-c># Body</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Async function example</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>async</span> <span class=pl-k>def</span> <span class=pl-en>on_update</span>(<span class=pl-s1>value</span>: <span class=pl-s1>str</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-c1>None</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    ...  <span class=pl-c># Body</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-callable_annotation-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-callable_annotation-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>callback</span>: <span class=pl-v>Callable</span>[[<span class=pl-s1>str</span>], <span class=pl-v>Awaitable</span>[<span class=pl-c1>None</span>]] <span class=pl-c1>=</span> <span class=pl-s1>on_update</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/9a0f0ff577e8bcab2215ac92a548918e/raw/7fe2e24d32f7ca967366533052f486ef6dfd416d/callable_annotation.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/9a0f0ff577e8bcab2215ac92a548918e#file-callable_annotation-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          callable_annotation.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381069" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-callable_annotation-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="callable_annotation.py">
        <tbody><tr>
          <td id="file-callable_annotation-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-callable_annotation-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">collections</span>.<span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">Callable</span>, <span class="pl-v">Awaitable</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-callable_annotation-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-callable_annotation-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Function with callable parameter</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-callable_annotation-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">feeder</span>(<span class="pl-s1">get_next_item</span>: <span class="pl-v">Callable</span>[[], <span class="pl-s1">str</span>]) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-callable_annotation-py-LC5" class="blob-code blob-code-inner js-file-line">    ...  <span class="pl-c"># Body</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-callable_annotation-py-LC6" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-callable_annotation-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Function with multiple callable parameters</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-callable_annotation-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">async_query</span>(<span class="pl-s1">on_success</span>: <span class="pl-v">Callable</span>[[<span class="pl-s1">int</span>], <span class="pl-c1">None</span>],</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-callable_annotation-py-LC9" class="blob-code blob-code-inner js-file-line">                <span class="pl-s1">on_error</span>: <span class="pl-v">Callable</span>[[<span class="pl-s1">int</span>, <span class="pl-v">Exception</span>], <span class="pl-c1">None</span>]) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-callable_annotation-py-LC10" class="blob-code blob-code-inner js-file-line">    ...  <span class="pl-c"># Body</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-callable_annotation-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-callable_annotation-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Async function example</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-callable_annotation-py-LC13" class="blob-code blob-code-inner js-file-line"><span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">on_update</span>(<span class="pl-s1">value</span>: <span class="pl-s1">str</span>) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-callable_annotation-py-LC14" class="blob-code blob-code-inner js-file-line">    ...  <span class="pl-c"># Body</span></td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-callable_annotation-py-LC15" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-callable_annotation-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-callable_annotation-py-LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">callback</span>: <span class="pl-v">Callable</span>[[<span class="pl-s1">str</span>], <span class="pl-v">Awaitable</span>[<span class="pl-c1">None</span>]] <span class="pl-c1">=</span> <span class="pl-s1">on_update</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/9a0f0ff577e8bcab2215ac92a548918e/raw/7fe2e24d32f7ca967366533052f486ef6dfd416d/callable_annotation.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/9a0f0ff577e8bcab2215ac92a548918e#file-callable_annotation-py" class="Link--inTextBlock">
          callable_annotation.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>The subscription syntax for <strong>Callable</strong> requires two values: the argument list and the return type. Using an ellipsis <code>...</code> as the argument list indicates that any parameter list is acceptable:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381097\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-any_callable-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;any_callable.py\&quot;>\n        <tr>\n          <td id=\&quot;file-any_callable-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-any_callable-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>concat</span>(<span class=pl-s1>x</span>: <span class=pl-s1>str</span>, <span class=pl-s1>y</span>: <span class=pl-s1>str</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any_callable-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-any_callable-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-s1>x</span> <span class=pl-c1>+</span> <span class=pl-s1>y</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any_callable-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-any_callable-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any_callable-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-any_callable-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>x</span>: <span class=pl-v>Callable</span>[..., <span class=pl-s1>str</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any_callable-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-any_callable-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>x</span> <span class=pl-c1>=</span> <span class=pl-s1>str</span>     <span class=pl-c># OK</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any_callable-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-any_callable-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>x</span> <span class=pl-c1>=</span> <span class=pl-s1>concat</span>  <span class=pl-c># Also OK</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/4fe812af27e05c991501160d4a803bb9/raw/1b2de8af9733534fc694156f2f4040f243c0c388/any_callable.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/4fe812af27e05c991501160d4a803bb9#file-any_callable-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          any_callable.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381097" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-any_callable-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="any_callable.py">
        <tbody><tr>
          <td id="file-any_callable-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-any_callable-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">concat</span>(<span class="pl-s1">x</span>: <span class="pl-s1">str</span>, <span class="pl-s1">y</span>: <span class="pl-s1">str</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-any_callable-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-any_callable-py-LC2" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-s1">x</span> <span class="pl-c1">+</span> <span class="pl-s1">y</span></td>
        </tr>
        <tr>
          <td id="file-any_callable-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-any_callable-py-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-any_callable-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-any_callable-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">x</span>: <span class="pl-v">Callable</span>[..., <span class="pl-s1">str</span>]</td>
        </tr>
        <tr>
          <td id="file-any_callable-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-any_callable-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">str</span>     <span class="pl-c"># OK</span></td>
        </tr>
        <tr>
          <td id="file-any_callable-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-any_callable-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">concat</span>  <span class="pl-c"># Also OK</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/4fe812af27e05c991501160d4a803bb9/raw/1b2de8af9733534fc694156f2f4040f243c0c388/any_callable.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/4fe812af27e05c991501160d4a803bb9#file-any_callable-py" class="Link--inTextBlock">
          any_callable.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h1>Special types and forms</h1><h2>Self</h2><p><strong>Self</strong> can be used to reference to the instance of a class object the code is currently operating on. We&#8217;ve seen this a lot in part 1 of this series when working with classes, but an example is:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381129\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-self_example-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;self_example.py\&quot;>\n        <tr>\n          <td id=\&quot;file-self_example-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>SQLDataSource</span>(<span class=pl-v>DataSource</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>connection_params</span> <span class=pl-c1>=</span> {}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>classmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>configure</span>(<span class=pl-s1>cls</span>, <span class=pl-s1>config</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>cls</span>.<span class=pl-s1>connection_params</span> <span class=pl-c1>=</span> <span class=pl-s1>config</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Configured SQL database with parameters: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>cls</span>.<span class=pl-s1>connection_params</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>execute_query</span>(<span class=pl-s1>self</span>, <span class=pl-s1>query</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-self_example-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-self_example-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Executing SQL query: &amp;#39;<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>query</span><span class=pl-kos>}</span></span>&amp;#39; with parameters <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>connection_params</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/904197bdf58e448c47e1e4f1405530e9/raw/98c5907c74f17843782b05b4ef22fbe01512d23b/self_example.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/904197bdf58e448c47e1e4f1405530e9#file-self_example-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          self_example.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381129" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-self_example-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="self_example.py">
        <tbody><tr>
          <td id="file-self_example-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-self_example-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">SQLDataSource</span>(<span class="pl-v">DataSource</span>):</td>
        </tr>
        <tr>
          <td id="file-self_example-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-self_example-py-LC2" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">connection_params</span> <span class="pl-c1">=</span> {}</td>
        </tr>
        <tr>
          <td id="file-self_example-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-self_example-py-LC3" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-self_example-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-self_example-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">classmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-self_example-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-self_example-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">configure</span>(<span class="pl-s1">cls</span>, <span class="pl-s1">config</span>):</td>
        </tr>
        <tr>
          <td id="file-self_example-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-self_example-py-LC6" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">cls</span>.<span class="pl-s1">connection_params</span> <span class="pl-c1">=</span> <span class="pl-s1">config</span></td>
        </tr>
        <tr>
          <td id="file-self_example-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-self_example-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Configured SQL database with parameters: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">cls</span>.<span class="pl-s1">connection_params</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-self_example-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-self_example-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-self_example-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-self_example-py-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">execute_query</span>(<span class="pl-s1">self</span>, <span class="pl-s1">query</span>):</td>
        </tr>
        <tr>
          <td id="file-self_example-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-self_example-py-LC10" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Executing SQL query: '<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">query</span><span class="pl-kos">}</span></span>' with parameters <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">connection_params</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/904197bdf58e448c47e1e4f1405530e9/raw/98c5907c74f17843782b05b4ef22fbe01512d23b/self_example.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/904197bdf58e448c47e1e4f1405530e9#file-self_example-py" class="Link--inTextBlock">
          self_example.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>This is useful for building out functionality between different components of your class.</p><h2>Any</h2><p>The <strong>Any</strong> type simply indicates a object can be of any type. As such it does not convey any additional information other than indicating to static code checkers this variable can be any type.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381166\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-any-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;any.py\&quot;>\n        <tr>\n          <td id=\&quot;file-any-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-any-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>Any</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-any-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-any-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>process_item</span>(<span class=pl-s1>item</span>: <span class=pl-v>Any</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-c1>None</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-any-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;Processing item: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>item</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-any-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-any-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage examples</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-any-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>process_item</span>(<span class=pl-c1>123</span>)          <span class=pl-c># Processing an integer</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-any-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>process_item</span>(<span class=pl-s>&amp;quot;Hello&amp;quot;</span>)      <span class=pl-c># Processing a string</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-any-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-any-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>process_item</span>([<span class=pl-c1>1</span>, <span class=pl-c1>2</span>, <span class=pl-c1>3</span>])    <span class=pl-c># Processing a list</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/6553d38d48d07c8e6309584ead39bbec/raw/fb0ab33b5673a993cbf566fa15a9237270c999e2/any.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/6553d38d48d07c8e6309584ead39bbec#file-any-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          any.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381166" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-any-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="any.py">
        <tbody><tr>
          <td id="file-any-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-any-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Any</span></td>
        </tr>
        <tr>
          <td id="file-any-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-any-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-any-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-any-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">process_item</span>(<span class="pl-s1">item</span>: <span class="pl-v">Any</span>) <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:</td>
        </tr>
        <tr>
          <td id="file-any-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-any-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">f"Processing item: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">item</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-any-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-any-py-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-any-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-any-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage examples</span></td>
        </tr>
        <tr>
          <td id="file-any-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-any-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-en">process_item</span>(<span class="pl-c1">123</span>)          <span class="pl-c"># Processing an integer</span></td>
        </tr>
        <tr>
          <td id="file-any-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-any-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-en">process_item</span>(<span class="pl-s">"Hello"</span>)      <span class="pl-c"># Processing a string</span></td>
        </tr>
        <tr>
          <td id="file-any-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-any-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-en">process_item</span>([<span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>])    <span class="pl-c"># Processing a list</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/6553d38d48d07c8e6309584ead39bbec/raw/fb0ab33b5673a993cbf566fa15a9237270c999e2/any.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/6553d38d48d07c8e6309584ead39bbec#file-any-py" class="Link--inTextBlock">
          any.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>Use this construct sparingly as using this a lot usually indicates you are not clear on the functioning of your code. If you are in the need of defining a generic function working on various types, use a <strong>TypeVar</strong> instead:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381174\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-typevar-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;typevar.py\&quot;>\n        <tr>\n          <td id=\&quot;file-typevar-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>TypeVar</span>, <span class=pl-v>List</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-v>T</span> <span class=pl-c1>=</span> <span class=pl-v>TypeVar</span>(<span class=pl-s>&amp;#39;T&amp;#39;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>duplicate</span>(<span class=pl-s1>item</span>: <span class=pl-v>T</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-v>List</span>[<span class=pl-v>T</span>]:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> [<span class=pl-s1>item</span>, <span class=pl-s1>item</span>]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage examples</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>duplicate</span>(<span class=pl-c1>123</span>))          <span class=pl-c># [123, 123]</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>duplicate</span>(<span class=pl-s>&amp;quot;Hello&amp;quot;</span>))      <span class=pl-c># [&amp;#39;Hello&amp;#39;, &amp;#39;Hello&amp;#39;]</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typevar-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-typevar-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>duplicate</span>([<span class=pl-c1>1</span>, <span class=pl-c1>2</span>, <span class=pl-c1>3</span>]))    <span class=pl-c># [[1, 2, 3], [1, 2, 3]]</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/d11c768b9161b9fcb75a48f9d6540319/raw/0a004ad518bee1e90871dba0c9384dcb83bd865e/typevar.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/d11c768b9161b9fcb75a48f9d6540319#file-typevar-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          typevar.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381174" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-typevar-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="typevar.py">
        <tbody><tr>
          <td id="file-typevar-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-typevar-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">TypeVar</span>, <span class="pl-v">List</span></td>
        </tr>
        <tr>
          <td id="file-typevar-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-typevar-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typevar-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-typevar-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-v">T</span> <span class="pl-c1">=</span> <span class="pl-v">TypeVar</span>(<span class="pl-s">'T'</span>)</td>
        </tr>
        <tr>
          <td id="file-typevar-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-typevar-py-LC4" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typevar-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-typevar-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">duplicate</span>(<span class="pl-s1">item</span>: <span class="pl-v">T</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">List</span>[<span class="pl-v">T</span>]:</td>
        </tr>
        <tr>
          <td id="file-typevar-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-typevar-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> [<span class="pl-s1">item</span>, <span class="pl-s1">item</span>]</td>
        </tr>
        <tr>
          <td id="file-typevar-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-typevar-py-LC7" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typevar-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-typevar-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage examples</span></td>
        </tr>
        <tr>
          <td id="file-typevar-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-typevar-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">duplicate</span>(<span class="pl-c1">123</span>))          <span class="pl-c"># [123, 123]</span></td>
        </tr>
        <tr>
          <td id="file-typevar-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-typevar-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">duplicate</span>(<span class="pl-s">"Hello"</span>))      <span class="pl-c"># ['Hello', 'Hello']</span></td>
        </tr>
        <tr>
          <td id="file-typevar-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-typevar-py-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">duplicate</span>([<span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>]))    <span class="pl-c"># [[1, 2, 3], [1, 2, 3]]</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/d11c768b9161b9fcb75a48f9d6540319/raw/0a004ad518bee1e90871dba0c9384dcb83bd865e/typevar.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/d11c768b9161b9fcb75a48f9d6540319#file-typevar-py" class="Link--inTextBlock">
          typevar.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>Generally, typevar is better because:</p><ol><li><p><strong>Type Safety</strong>: <strong>TypeVar</strong> helps maintain type consistency, which means the function or class can work with any type while ensuring that the same type is used throughout. This prevents type-related errors that could occur if different types are inadvertently mixed.</p></li><li><p><strong>Code Readability and Intent</strong>: Using <strong>TypeVar</strong> clearly communicates the intent that a function or class is designed to be generic and work with any type, but consistently. This makes the code easier to understand and maintain.</p></li><li><p><strong>Static Type Checking</strong>: Type checkers (like mypy) can provide better error checking and autocompletion support when <strong>TypeVar</strong> is used. This can catch potential bugs at development time instead of runtime.</p></li></ol><h2>Union</h2><p><strong>Union</strong> is a typing construct that indicates the object it is encapsulating can be either type.</p><p>For example writing <strong>Union[str,int]</strong> defines a object as being <strong>either</strong> a string or an integer. Please do note this also means that when you define <strong>Union</strong> on a generic type which can be paramterized with another type like <strong>dict[Union[str,int]]</strong> , this will accept dictionaries that contain <strong>all strings</strong>,<strong> all ints</strong> <strong>or a combination of the two</strong>. </p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381318\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-union-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;union.py\&quot;>\n        <tr>\n          <td id=\&quot;file-union-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-union-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>Union</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-union-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-union-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>process_record</span>(<span class=pl-s1>record_id</span>: <span class=pl-v>Union</span>[<span class=pl-s1>str</span>, <span class=pl-s1>int</span>]) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-union-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>if</span> <span class=pl-en>isinstance</span>(<span class=pl-s1>record_id</span>, <span class=pl-s1>str</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-union-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Processing record with string ID: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>record_id</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-union-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>elif</span> <span class=pl-en>isinstance</span>(<span class=pl-s1>record_id</span>, <span class=pl-s1>int</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-union-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Processing record with integer ID: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>record_id</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-union-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>else</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-union-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>&amp;quot;Unsupported record ID type&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-union-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-union-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>process_record</span>(<span class=pl-s>&amp;quot;abc123&amp;quot;</span>))  <span class=pl-c># Output: Processing record with string ID: abc123</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-union-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-union-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>process_record</span>(<span class=pl-c1>456789</span>))    <span class=pl-c># Output: Processing record with integer ID: 456789</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/4a2517f656be2c432d1aac3df928c11e/raw/8c147f951ab246c0c7048ebb278ef028dab2be63/union.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/4a2517f656be2c432d1aac3df928c11e#file-union-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          union.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381318" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-union-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="union.py">
        <tbody><tr>
          <td id="file-union-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-union-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Union</span></td>
        </tr>
        <tr>
          <td id="file-union-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-union-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-union-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-union-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">process_record</span>(<span class="pl-s1">record_id</span>: <span class="pl-v">Union</span>[<span class="pl-s1">str</span>, <span class="pl-s1">int</span>]) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-union-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-union-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">record_id</span>, <span class="pl-s1">str</span>):</td>
        </tr>
        <tr>
          <td id="file-union-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-union-py-LC5" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Processing record with string ID: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">record_id</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-union-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-union-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">elif</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">record_id</span>, <span class="pl-s1">int</span>):</td>
        </tr>
        <tr>
          <td id="file-union-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-union-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Processing record with integer ID: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">record_id</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-union-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-union-py-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">else</span>:</td>
        </tr>
        <tr>
          <td id="file-union-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-union-py-LC9" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">"Unsupported record ID type"</span></td>
        </tr>
        <tr>
          <td id="file-union-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-union-py-LC10" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-union-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-union-py-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">process_record</span>(<span class="pl-s">"abc123"</span>))  <span class="pl-c"># Output: Processing record with string ID: abc123</span></td>
        </tr>
        <tr>
          <td id="file-union-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-union-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">process_record</span>(<span class="pl-c1">456789</span>))    <span class="pl-c"># Output: Processing record with integer ID: 456789</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/4a2517f656be2c432d1aac3df928c11e/raw/8c147f951ab246c0c7048ebb278ef028dab2be63/union.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/4a2517f656be2c432d1aac3df928c11e#file-union-py" class="Link--inTextBlock">
          union.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><blockquote><p>Please be aware of this distinction: Union does NOT cover the case where we are using strings and integers mixed together. Rather, it&#8217;s an either or. </p></blockquote><p>For dictionaries in specific, it is worth exploring the <a href="https://docs.python.org/3/library/typing.html#typing.TypedDict">TypedDict</a> which allows you to define more explicit typing on specific types of keys van values.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381332\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-typedict-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;typedict.py\&quot;>\n        <tr>\n          <td id=\&quot;file-typedict-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>TypedDict</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DataPipelineConfig</span>(<span class=pl-v>TypedDict</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>name</span>: <span class=pl-s1>str</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>batch_size</span>: <span class=pl-s1>int</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>is_active</span>: <span class=pl-s1>bool</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>display_pipeline_config</span>(<span class=pl-s1>config</span>: <span class=pl-v>DataPipelineConfig</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>status</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;#39;active&amp;#39;</span> <span class=pl-k>if</span> <span class=pl-s1>config</span>[<span class=pl-s>&amp;#39;is_active&amp;#39;</span>] <span class=pl-k>else</span> <span class=pl-s>&amp;#39;inactive&amp;#39;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> (<span class=pl-s>f&amp;quot;Pipeline <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>config</span>[<span class=pl-s>&amp;#39;name&amp;#39;</span>]<span class=pl-kos>}</span></span> with batch size <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>config</span>[<span class=pl-s>&amp;#39;batch_size&amp;#39;</span>]<span class=pl-kos>}</span></span> is currently <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>status</span><span class=pl-kos>}</span></span>.&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>pipeline_config</span>: <span class=pl-v>DataPipelineConfig</span> <span class=pl-c1>=</span> {</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;name&amp;quot;</span>: <span class=pl-s>&amp;quot;User ETL&amp;quot;</span>,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;batch_size&amp;quot;</span>: <span class=pl-c1>1000</span>,</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;is_active&amp;quot;</span>: <span class=pl-c1>True</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>display_pipeline_config</span>(<span class=pl-s1>pipeline_config</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-typedict-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-typedict-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: Pipeline User ETL with batch size 1000 is currently active.</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/cbcb0b02fde1b8542fcd1943eef5e158/raw/202a610108520d991f0fcf5366289ffcabec57b2/typedict.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/cbcb0b02fde1b8542fcd1943eef5e158#file-typedict-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          typedict.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381332" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-typedict-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="typedict.py">
        <tbody><tr>
          <td id="file-typedict-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-typedict-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">TypedDict</span></td>
        </tr>
        <tr>
          <td id="file-typedict-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-typedict-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-typedict-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DataPipelineConfig</span>(<span class="pl-v">TypedDict</span>):</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-typedict-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">name</span>: <span class="pl-s1">str</span></td>
        </tr>
        <tr>
          <td id="file-typedict-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-typedict-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">batch_size</span>: <span class="pl-s1">int</span></td>
        </tr>
        <tr>
          <td id="file-typedict-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-typedict-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">is_active</span>: <span class="pl-s1">bool</span></td>
        </tr>
        <tr>
          <td id="file-typedict-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-typedict-py-LC7" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-typedict-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">display_pipeline_config</span>(<span class="pl-s1">config</span>: <span class="pl-v">DataPipelineConfig</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-typedict-py-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">status</span> <span class="pl-c1">=</span> <span class="pl-s">'active'</span> <span class="pl-k">if</span> <span class="pl-s1">config</span>[<span class="pl-s">'is_active'</span>] <span class="pl-k">else</span> <span class="pl-s">'inactive'</span></td>
        </tr>
        <tr>
          <td id="file-typedict-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-typedict-py-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> (<span class="pl-s">f"Pipeline <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">config</span>[<span class="pl-s">'name'</span>]<span class="pl-kos">}</span></span> with batch size <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">config</span>[<span class="pl-s">'batch_size'</span>]<span class="pl-kos">}</span></span> is currently <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">status</span><span class="pl-kos">}</span></span>."</span>)</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-typedict-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-typedict-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">pipeline_config</span>: <span class="pl-v">DataPipelineConfig</span> <span class="pl-c1">=</span> {</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-typedict-py-LC13" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"name"</span>: <span class="pl-s">"User ETL"</span>,</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-typedict-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"batch_size"</span>: <span class="pl-c1">1000</span>,</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-typedict-py-LC15" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"is_active"</span>: <span class="pl-c1">True</span></td>
        </tr>
        <tr>
          <td id="file-typedict-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-typedict-py-LC16" class="blob-code blob-code-inner js-file-line">}</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-typedict-py-LC17" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-typedict-py-LC18" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">display_pipeline_config</span>(<span class="pl-s1">pipeline_config</span>))</td>
        </tr>
        <tr>
          <td id="file-typedict-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-typedict-py-LC19" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: Pipeline User ETL with batch size 1000 is currently active.</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/cbcb0b02fde1b8542fcd1943eef5e158/raw/202a610108520d991f0fcf5366289ffcabec57b2/typedict.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/cbcb0b02fde1b8542fcd1943eef5e158#file-typedict-py" class="Link--inTextBlock">
          typedict.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>Generally however, if you need to be this elaborate with typing, it usually makes sense to define a <strong>dataclass</strong> or<strong> pydantic model</strong> instead (more on that in part 3).</p><h2>Optional</h2><p>As the name implies, optional indicates a object is optional. This is most often seen with optional class attributes that are only used within specific contexts.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381375\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-optional-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;optional.py\&quot;>\n        <tr>\n          <td id=\&quot;file-optional-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-optional-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>Optional</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-optional-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-optional-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>process_data</span>(<span class=pl-s1>file_path</span>: <span class=pl-s1>str</span>, <span class=pl-s1>delimiter</span>: <span class=pl-v>Optional</span>[<span class=pl-s1>str</span>] <span class=pl-c1>=</span> <span class=pl-c1>None</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-optional-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>delimiter_info</span> <span class=pl-c1>=</span> <span class=pl-s>f&amp;quot; with delimiter &amp;#39;<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>delimiter</span><span class=pl-kos>}</span></span>&amp;#39;&amp;quot;</span> <span class=pl-k>if</span> <span class=pl-s1>delimiter</span> <span class=pl-k>else</span> <span class=pl-s>&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-optional-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Processing file at <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>file_path</span><span class=pl-kos>}</span></span><span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>delimiter_info</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-optional-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-optional-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>process_data</span>(<span class=pl-s>&amp;quot;/path/to/file.csv&amp;quot;</span>))  <span class=pl-c># Output: Processing file at /path/to/file.csv</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-optional-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-optional-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>process_data</span>(<span class=pl-s>&amp;quot;/path/to/file.csv&amp;quot;</span>, <span class=pl-s>&amp;quot;,&amp;quot;</span>))  <span class=pl-c># Output: Processing file at /path/to/file.csv with delimiter &amp;#39;,&amp;#39;</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/fcc6070a4083a6c31cad903da29866cd/raw/964017f7387aeacbe44a71b279aeb1d20f4d8571/optional.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/fcc6070a4083a6c31cad903da29866cd#file-optional-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          optional.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381375" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-optional-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="optional.py">
        <tbody><tr>
          <td id="file-optional-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-optional-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Optional</span></td>
        </tr>
        <tr>
          <td id="file-optional-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-optional-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-optional-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-optional-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">process_data</span>(<span class="pl-s1">file_path</span>: <span class="pl-s1">str</span>, <span class="pl-s1">delimiter</span>: <span class="pl-v">Optional</span>[<span class="pl-s1">str</span>] <span class="pl-c1">=</span> <span class="pl-c1">None</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-optional-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-optional-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">delimiter_info</span> <span class="pl-c1">=</span> <span class="pl-s">f" with delimiter '<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">delimiter</span><span class="pl-kos">}</span></span>'"</span> <span class="pl-k">if</span> <span class="pl-s1">delimiter</span> <span class="pl-k">else</span> <span class="pl-s">""</span></td>
        </tr>
        <tr>
          <td id="file-optional-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-optional-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-s">f"Processing file at <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">file_path</span><span class="pl-kos">}</span></span><span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">delimiter_info</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-optional-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-optional-py-LC6" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-optional-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-optional-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">process_data</span>(<span class="pl-s">"/path/to/file.csv"</span>))  <span class="pl-c"># Output: Processing file at /path/to/file.csv</span></td>
        </tr>
        <tr>
          <td id="file-optional-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-optional-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">process_data</span>(<span class="pl-s">"/path/to/file.csv"</span>, <span class="pl-s">","</span>))  <span class="pl-c"># Output: Processing file at /path/to/file.csv with delimiter ','</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/fcc6070a4083a6c31cad903da29866cd/raw/964017f7387aeacbe44a71b279aeb1d20f4d8571/optional.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/fcc6070a4083a6c31cad903da29866cd#file-optional-py" class="Link--inTextBlock">
          optional.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h2>Literal</h2><p>The literal type can be used to define a literal instance of a type. For example, type hinting with <strong>Literal[42]</strong> will indicate this object should always have a intenger value of <code>42</code> . This is useful for configuration-like objects that have a set of hard coded values. </p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381381\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-literal-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;literal.py\&quot;>\n        <tr>\n          <td id=\&quot;file-literal-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-literal-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>typing</span> <span class=pl-k>import</span> <span class=pl-v>Literal</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-literal-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-literal-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>set_environment</span>(<span class=pl-s1>env</span>: <span class=pl-v>Literal</span>[<span class=pl-s>&amp;quot;development&amp;quot;</span>, <span class=pl-s>&amp;quot;staging&amp;quot;</span>, <span class=pl-s>&amp;quot;production&amp;quot;</span>]) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-literal-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Environment set to <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>env</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-literal-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-literal-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>set_environment</span>(<span class=pl-s>&amp;quot;development&amp;quot;</span>))  <span class=pl-c># Output: Environment set to development</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-literal-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>set_environment</span>(<span class=pl-s>&amp;quot;production&amp;quot;</span>))  <span class=pl-c># Output: Environment set to production</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-literal-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-literal-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># The following would raise a type error with a type checker like mypy, as &amp;quot;test&amp;quot; is not a valid literal</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-literal-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-literal-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># print(set_environment(&amp;quot;test&amp;quot;))</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/b341b15c811475a15b3386751f0db93e/raw/c9b0db26137c155de8d0a062d7cd326f889d13e9/literal.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/b341b15c811475a15b3386751f0db93e#file-literal-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          literal.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381381" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-literal-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="literal.py">
        <tbody><tr>
          <td id="file-literal-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-literal-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">Literal</span></td>
        </tr>
        <tr>
          <td id="file-literal-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-literal-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-literal-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-literal-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">set_environment</span>(<span class="pl-s1">env</span>: <span class="pl-v">Literal</span>[<span class="pl-s">"development"</span>, <span class="pl-s">"staging"</span>, <span class="pl-s">"production"</span>]) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-literal-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-literal-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-s">f"Environment set to <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">env</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-literal-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-literal-py-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-literal-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-literal-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">set_environment</span>(<span class="pl-s">"development"</span>))  <span class="pl-c"># Output: Environment set to development</span></td>
        </tr>
        <tr>
          <td id="file-literal-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-literal-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">set_environment</span>(<span class="pl-s">"production"</span>))  <span class="pl-c"># Output: Environment set to production</span></td>
        </tr>
        <tr>
          <td id="file-literal-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-literal-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-literal-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-literal-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># The following would raise a type error with a type checker like mypy, as "test" is not a valid literal</span></td>
        </tr>
        <tr>
          <td id="file-literal-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-literal-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># print(set_environment("test"))</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/b341b15c811475a15b3386751f0db93e/raw/c9b0db26137c155de8d0a062d7cd326f889d13e9/literal.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/b341b15c811475a15b3386751f0db93e#file-literal-py" class="Link--inTextBlock">
          literal.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>If there is a larger amount of objects that depend on this configuration, it can be beneficial to define it as an <strong>enum</strong> instead.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381394\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-enum-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;enum.py\&quot;>\n        <tr>\n          <td id=\&quot;file-enum-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-enum-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>enum</span> <span class=pl-k>import</span> <span class=pl-v>Enum</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-enum-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-enum-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>Environment</span>(<span class=pl-v>Enum</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-enum-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-v>DEVELOPMENT</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;development&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-enum-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-v>STAGING</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;staging&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-enum-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-v>PRODUCTION</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;production&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-enum-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-enum-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>def</span> <span class=pl-en>set_environment</span>(<span class=pl-s1>env</span>: <span class=pl-v>Environment</span>) <span class=pl-c1>-&amp;gt;</span> <span class=pl-s1>str</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-enum-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Environment set to <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>env</span>.<span class=pl-s1>value</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-enum-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-enum-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>set_environment</span>(<span class=pl-v>Environment</span>.<span class=pl-v>DEVELOPMENT</span>))  <span class=pl-c># Output: Environment set to development</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-enum-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-enum-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>set_environment</span>(<span class=pl-v>Environment</span>.<span class=pl-v>PRODUCTION</span>))   <span class=pl-c># Output: Environment set to production</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/5114ae0190022ee7b61032f1665f1ac3/raw/4cb3f2bbf699065df26652cc25f79d5c3a7f488a/enum.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/5114ae0190022ee7b61032f1665f1ac3#file-enum-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          enum.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381394" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-enum-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="enum.py">
        <tbody><tr>
          <td id="file-enum-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-enum-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">enum</span> <span class="pl-k">import</span> <span class="pl-v">Enum</span></td>
        </tr>
        <tr>
          <td id="file-enum-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-enum-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-enum-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-enum-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">Environment</span>(<span class="pl-v">Enum</span>):</td>
        </tr>
        <tr>
          <td id="file-enum-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-enum-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-v">DEVELOPMENT</span> <span class="pl-c1">=</span> <span class="pl-s">"development"</span></td>
        </tr>
        <tr>
          <td id="file-enum-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-enum-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-v">STAGING</span> <span class="pl-c1">=</span> <span class="pl-s">"staging"</span></td>
        </tr>
        <tr>
          <td id="file-enum-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-enum-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-v">PRODUCTION</span> <span class="pl-c1">=</span> <span class="pl-s">"production"</span></td>
        </tr>
        <tr>
          <td id="file-enum-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-enum-py-LC7" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-enum-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-enum-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-k">def</span> <span class="pl-en">set_environment</span>(<span class="pl-s1">env</span>: <span class="pl-v">Environment</span>) <span class="pl-c1">-&gt;</span> <span class="pl-s1">str</span>:</td>
        </tr>
        <tr>
          <td id="file-enum-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-enum-py-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> <span class="pl-s">f"Environment set to <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">env</span>.<span class="pl-s1">value</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-enum-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-enum-py-LC10" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-enum-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-enum-py-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">set_environment</span>(<span class="pl-v">Environment</span>.<span class="pl-v">DEVELOPMENT</span>))  <span class="pl-c"># Output: Environment set to development</span></td>
        </tr>
        <tr>
          <td id="file-enum-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-enum-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">set_environment</span>(<span class="pl-v">Environment</span>.<span class="pl-v">PRODUCTION</span>))   <span class="pl-c"># Output: Environment set to production</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/5114ae0190022ee7b61032f1665f1ac3/raw/4cb3f2bbf699065df26652cc25f79d5c3a7f488a/enum.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/5114ae0190022ee7b61032f1665f1ac3#file-enum-py" class="Link--inTextBlock">
          enum.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h1>Inspecting types in classes</h1><p>Often when you are not too familiar with the inner workings objects in a code base or external library it can be difficult sometimes to determine the right type to use when laying out your typing system. In the past, I would have resorted to reading a bunch of source code to figure this out. It is also possible to determine this during run time by inspecting classes and variables.</p><h4><strong>Using </strong><code>vars</code></h4><p>The <code>vars</code> function returns the <code>__dict__</code> attribute of the given object, which contains all the attributes of the object.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381500\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-vars-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;vars.py\&quot;>\n        <tr>\n          <td id=\&quot;file-vars-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-vars-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DataPipeline</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-vars-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__init__</span>(<span class=pl-s1>self</span>, <span class=pl-s1>name</span>: <span class=pl-s1>str</span>, <span class=pl-s1>batch_size</span>: <span class=pl-s1>int</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-vars-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>name</span> <span class=pl-c1>=</span> <span class=pl-s1>name</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-vars-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>batch_size</span> <span class=pl-c1>=</span> <span class=pl-s1>batch_size</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-vars-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>status</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;inactive&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-vars-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-vars-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>pipeline</span> <span class=pl-c1>=</span> <span class=pl-v>DataPipeline</span>(<span class=pl-s1>name</span><span class=pl-c1>=</span><span class=pl-s>&amp;quot;ETL Pipeline&amp;quot;</span>, <span class=pl-s1>batch_size</span><span class=pl-c1>=</span><span class=pl-c1>500</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-vars-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>vars</span>(<span class=pl-s1>pipeline</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-vars-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-vars-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: {&amp;#39;name&amp;#39;: &amp;#39;ETL Pipeline&amp;#39;, &amp;#39;batch_size&amp;#39;: 500, &amp;#39;status&amp;#39;: &amp;#39;inactive&amp;#39;}</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/40c94ca7a20c21180d3db6001e1fc815/raw/b4dcbe8121ac1d152c66b5775e209ce2ec9f0353/vars.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/40c94ca7a20c21180d3db6001e1fc815#file-vars-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          vars.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381500" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-vars-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="vars.py">
        <tbody><tr>
          <td id="file-vars-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-vars-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DataPipeline</span>:</td>
        </tr>
        <tr>
          <td id="file-vars-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-vars-py-LC2" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">name</span>: <span class="pl-s1">str</span>, <span class="pl-s1">batch_size</span>: <span class="pl-s1">int</span>):</td>
        </tr>
        <tr>
          <td id="file-vars-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-vars-py-LC3" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">name</span> <span class="pl-c1">=</span> <span class="pl-s1">name</span></td>
        </tr>
        <tr>
          <td id="file-vars-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-vars-py-LC4" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">batch_size</span> <span class="pl-c1">=</span> <span class="pl-s1">batch_size</span></td>
        </tr>
        <tr>
          <td id="file-vars-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-vars-py-LC5" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">status</span> <span class="pl-c1">=</span> <span class="pl-s">"inactive"</span></td>
        </tr>
        <tr>
          <td id="file-vars-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-vars-py-LC6" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-vars-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-vars-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">pipeline</span> <span class="pl-c1">=</span> <span class="pl-v">DataPipeline</span>(<span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s">"ETL Pipeline"</span>, <span class="pl-s1">batch_size</span><span class="pl-c1">=</span><span class="pl-c1">500</span>)</td>
        </tr>
        <tr>
          <td id="file-vars-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-vars-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">vars</span>(<span class="pl-s1">pipeline</span>))</td>
        </tr>
        <tr>
          <td id="file-vars-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-vars-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: {'name': 'ETL Pipeline', 'batch_size': 500, 'status': 'inactive'}</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/40c94ca7a20c21180d3db6001e1fc815/raw/b4dcbe8121ac1d152c66b5775e209ce2ec9f0353/vars.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/40c94ca7a20c21180d3db6001e1fc815#file-vars-py" class="Link--inTextBlock">
          vars.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h4><strong>Using </strong><code>dir</code></h4><p>The <code>dir</code> function returns a list of all the attributes and methods of the given object.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381517\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-dir-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;dir.py\&quot;>\n        <tr>\n          <td id=\&quot;file-dir-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-dir-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>dir</span>(<span class=pl-s1>pipeline</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dir-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-dir-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: [&amp;#39;__class__&amp;#39;, &amp;#39;__delattr__&amp;#39;, &amp;#39;__dict__&amp;#39;, &amp;#39;__dir__&amp;#39;, &amp;#39;__doc__&amp;#39;, &amp;#39;__eq__&amp;#39;, &amp;#39;__format__&amp;#39;, &amp;#39;__ge__&amp;#39;, &amp;#39;__getattribute__&amp;#39;, &amp;#39;__gt__&amp;#39;, &amp;#39;__hash__&amp;#39;, &amp;#39;__init__&amp;#39;, &amp;#39;__init_subclass__&amp;#39;, &amp;#39;__le__&amp;#39;, &amp;#39;__lt__&amp;#39;, &amp;#39;__module__&amp;#39;, &amp;#39;__ne__&amp;#39;, &amp;#39;__new__&amp;#39;, &amp;#39;__reduce__&amp;#39;, &amp;#39;__reduce_ex__&amp;#39;, &amp;#39;__repr__&amp;#39;, &amp;#39;__setattr__&amp;#39;, &amp;#39;__sizeof__&amp;#39;, &amp;#39;__str__&amp;#39;, &amp;#39;__subclasshook__&amp;#39;, &amp;#39;__weakref__&amp;#39;, &amp;#39;batch_size&amp;#39;, &amp;#39;name&amp;#39;, &amp;#39;status&amp;#39;]</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/40edb6a45e88983f59ddba1f4b6cc849/raw/35fd422b7b09a4e741b0246cf233410773d524cc/dir.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/40edb6a45e88983f59ddba1f4b6cc849#file-dir-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          dir.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381517" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-dir-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="dir.py">
        <tbody><tr>
          <td id="file-dir-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-dir-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">dir</span>(<span class="pl-s1">pipeline</span>))</td>
        </tr>
        <tr>
          <td id="file-dir-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-dir-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'batch_size', 'name', 'status']</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/40edb6a45e88983f59ddba1f4b6cc849/raw/35fd422b7b09a4e741b0246cf233410773d524cc/dir.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/40edb6a45e88983f59ddba1f4b6cc849#file-dir-py" class="Link--inTextBlock">
          dir.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h4><strong>Using </strong><code>type</code></h4><p>The <code>type</code> function returns the type of the given object.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381530\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-type-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;type.py\&quot;>\n        <tr>\n          <td id=\&quot;file-type-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-type-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>type</span>(<span class=pl-s1>pipeline</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-type-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: &amp;lt;class &amp;#39;__main__.DataPipeline&amp;#39;&amp;gt;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-type-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>type</span>(<span class=pl-s1>pipeline</span>.<span class=pl-s1>name</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-type-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: &amp;lt;class &amp;#39;str&amp;#39;&amp;gt;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-type-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-en>type</span>(<span class=pl-s1>pipeline</span>.<span class=pl-s1>batch_size</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-type-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-type-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: &amp;lt;class &amp;#39;int&amp;#39;&amp;gt;</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/0f3e472fb53d3aede1ed821b4e4467ba/raw/6b24bf4cc31a2d84decf09f4458c7678a9e3a23d/type.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/0f3e472fb53d3aede1ed821b4e4467ba#file-type-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          type.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381530" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-type-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="type.py">
        <tbody><tr>
          <td id="file-type-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-type-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">type</span>(<span class="pl-s1">pipeline</span>))</td>
        </tr>
        <tr>
          <td id="file-type-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-type-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: &lt;class '__main__.DataPipeline'&gt;</span></td>
        </tr>
        <tr>
          <td id="file-type-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-type-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">type</span>(<span class="pl-s1">pipeline</span>.<span class="pl-s1">name</span>))</td>
        </tr>
        <tr>
          <td id="file-type-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-type-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: &lt;class 'str'&gt;</span></td>
        </tr>
        <tr>
          <td id="file-type-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-type-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-en">type</span>(<span class="pl-s1">pipeline</span>.<span class="pl-s1">batch_size</span>))</td>
        </tr>
        <tr>
          <td id="file-type-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-type-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: &lt;class 'int'&gt;</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/0f3e472fb53d3aede1ed821b4e4467ba/raw/6b24bf4cc31a2d84decf09f4458c7678a9e3a23d/type.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/0f3e472fb53d3aede1ed821b4e4467ba#file-type-py" class="Link--inTextBlock">
          type.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h4><strong>Using the </strong><code>inspect</code> Library</h4><p>The <code>inspect</code> library provides several useful functions to get information about live objects, such as modules, classes, methods, functions, tracebacks, and code objects.</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist130381538\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-inspect-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;inspect.py\&quot;>\n        <tr>\n          <td id=\&quot;file-inspect-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>inspect</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Get the class definition of the object</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-s1>inspect</span>.<span class=pl-en>getmembers</span>(<span class=pl-s1>pipeline</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: [(&amp;#39;__class__&amp;#39;, &amp;lt;class &amp;#39;__main__.DataPipeline&amp;#39;&amp;gt;), (&amp;#39;__delattr__&amp;#39;, &amp;lt;method-wrapper &amp;#39;__delattr__&amp;#39; of DataPipeline object at 0x7f8b6f3b1f10&amp;gt;), (&amp;#39;__dict__&amp;#39;, {&amp;#39;name&amp;#39;: &amp;#39;ETL Pipeline&amp;#39;, &amp;#39;batch_size&amp;#39;: 500, &amp;#39;status&amp;#39;: &amp;#39;inactive&amp;#39;}), (&amp;#39;__dir__&amp;#39;, &amp;lt;built-in method __dir__ of DataPipeline object at 0x7f8b6f3b1f10&amp;gt;), ...]</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Get the signature of the __init__ method</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-s1>inspect</span>.<span class=pl-en>signature</span>(<span class=pl-v>DataPipeline</span>.<span class=pl-s1>__init__</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-inspect-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-inspect-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Output: (self, name: str, batch_size: int)</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/ee3c34c326f02b58e50d6e263bf9dbee/raw/d42966bfc35167c0f9eb42e1fb958a208e4b73f0/inspect.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/ee3c34c326f02b58e50d6e263bf9dbee#file-inspect-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          inspect.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-8c1a5bab9782.css"><div id="gist130381538" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-inspect-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="inspect.py">
        <tbody><tr>
          <td id="file-inspect-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-inspect-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">inspect</span></td>
        </tr>
        <tr>
          <td id="file-inspect-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-inspect-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-inspect-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-inspect-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Get the class definition of the object</span></td>
        </tr>
        <tr>
          <td id="file-inspect-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-inspect-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-s1">inspect</span>.<span class="pl-en">getmembers</span>(<span class="pl-s1">pipeline</span>))</td>
        </tr>
        <tr>
          <td id="file-inspect-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-inspect-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: [('__class__', &lt;class '__main__.DataPipeline'&gt;), ('__delattr__', &lt;method-wrapper '__delattr__' of DataPipeline object at 0x7f8b6f3b1f10&gt;), ('__dict__', {'name': 'ETL Pipeline', 'batch_size': 500, 'status': 'inactive'}), ('__dir__', &lt;built-in method __dir__ of DataPipeline object at 0x7f8b6f3b1f10&gt;), ...]</span></td>
        </tr>
        <tr>
          <td id="file-inspect-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-inspect-py-LC6" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-inspect-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-inspect-py-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Get the signature of the __init__ method</span></td>
        </tr>
        <tr>
          <td id="file-inspect-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-inspect-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-s1">inspect</span>.<span class="pl-en">signature</span>(<span class="pl-v">DataPipeline</span>.<span class="pl-s1">__init__</span>))</td>
        </tr>
        <tr>
          <td id="file-inspect-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-inspect-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Output: (self, name: str, batch_size: int)</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/ee3c34c326f02b58e50d6e263bf9dbee/raw/d42966bfc35167c0f9eb42e1fb958a208e4b73f0/inspect.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/ee3c34c326f02b58e50d6e263bf9dbee#file-inspect-py" class="Link--inTextBlock">
          inspect.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>These methods and functions can help you inspect and understand the types used in classes and objects, making it easier to implement type hinting and understand the structure of unfamiliar codebases.</p><div><hr></div><p>With that, we&#8217;re going to conclude this section on python typing. Do note again that this is a massive topic in python and we&#8217;ve just scratched the surface here.</p><p>Moving on, you may wonder (or know) that typing and type hints in and of themselves don&#8217;t <strong>enforce</strong> anything in your code. This is the natural design of python as a dynamically typed language.</p><p>However, how can we take these typing constructs and actually do something in our code other than document things? This is where a framework like <strong>pydantic</strong> comes into play. In the following section, we will describe how to use <strong>pydantic</strong> to create data models in your code that leverage our previous knowledge on abstract base classes and typing to create a much more powerful data code model.</p><h1>If you liked this and want to read more, please support the newsletter with a subscribe</h1><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Data Code Modelling: Abstract Base Classes]]></title><description><![CDATA[Building robust code for data engineering workflows.]]></description><link>https://www.blog.zelytics.tech/p/data-code-modelling-abstract-base</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/data-code-modelling-abstract-base</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Sun, 28 Apr 2024 08:54:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!LRg1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p><p>When working in data engineering, you will often have to work with python code bases to manage all sorts of processes in your data stack from ETL, to orchestration, to infrastructure management, to observability and much more. </p><p>One view of data engineering is that of a blend of software engineering and data science. Oftentimes as data engineers, we will spend time learning about general code best practises in software engineering and try to apply them to our domain. </p><p>However, a lot of the times these general principles fall short of the standards we would like to achieve. </p><p>On top of that, there has been a lot of development of python and the ecosystem around it so it&#8217;s possible to be a lot more intentional about our code design.</p><h1>The big picture</h1><p>Let&#8217;s take a step back and think about the bigger picture here. Python as a language is a strongly but a dynamically typed language. Simply put, python has a strict type system but how it used during runtime is flexible. If designed for then, python can get a lot closer (though not quite) to the type safety provided by statically strong typed languages.</p><p>Although the default configuration of python code is fine for development, for production systems we want a lot more guarantees about the consistency of our code. This is where a data code model comes into play. This is different for every project, but this article and follow up articles will provide a framework by which you can make your own informed decisions. </p><p>Creating a solid code data model leads to dramatically different trajectories for the amount of scope a team can handle.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LRg1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LRg1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 424w, https://substackcdn.com/image/fetch/$s_!LRg1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 848w, https://substackcdn.com/image/fetch/$s_!LRg1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 1272w, https://substackcdn.com/image/fetch/$s_!LRg1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LRg1!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png" width="1200" height="449.1758241758242" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:545,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:545754,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LRg1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 424w, https://substackcdn.com/image/fetch/$s_!LRg1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 848w, https://substackcdn.com/image/fetch/$s_!LRg1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 1272w, https://substackcdn.com/image/fetch/$s_!LRg1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8fcf3ed-6b36-4508-806f-d16e805830da_5824x2179.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When the focus is solely <strong>&#8220;ship fast - fix later&#8221;</strong>, this builds tech debt until a <strong>point of critical stress. </strong>At this point, the code base is bearing so much technical debt your teams time is absorbed with bug fixes, ad-hoc requests, refactoring and more. Development velocity reduces significantly until a <strong>point of legacy </strong>is reached. At this point, there is too many features, dependencies and dollars at stake to change trajectory so the company is left with a legacy code base which becomes increasingly slower to change.</p><p>When working with a proper code data model, initial velocity is lower. However, after some initial hurdles you reach a <strong>point of bliss</strong> after which developing more features and complexity becomes exponentially more easy until a higher level of peak complexity is reached.</p><p>Some of the reasons why is:</p><ul><li><p>Improved readability &#8594; Less documentation burden.</p></li><li><p>Lower fragility of code changes &#8594; higher development velocity.</p></li><li><p>Faster time to resolution on bugs &#8594; Better uptime.</p></li><li><p>Static and runtime controls &#8594; Less need for extensive unit testing</p></li><li><p>A higher capacity for complexity and features &#8594; More value, lower costs</p></li></ul><p>So then, how to go at this concretely? In this article series, I will go over the <strong>data code model </strong>to structure your python code for data engineering. In this article, I will focus on the first component: <strong>Abstract Base Classes</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BUp8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BUp8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 424w, https://substackcdn.com/image/fetch/$s_!BUp8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 848w, https://substackcdn.com/image/fetch/$s_!BUp8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 1272w, https://substackcdn.com/image/fetch/$s_!BUp8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BUp8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png" width="1456" height="1745" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1745,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:715589,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BUp8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 424w, https://substackcdn.com/image/fetch/$s_!BUp8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 848w, https://substackcdn.com/image/fetch/$s_!BUp8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 1272w, https://substackcdn.com/image/fetch/$s_!BUp8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc087369-5f22-4f41-8233-223cc056ad0d_3446x4131.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>Layer 1: Abstract Base Classes</h1><p>Abstract Base Classes (ABCs) in Python serve as templates for other classes. They outline a set of definitions that must be created in any subclass that inherits from them. The primary purpose of ABCs is to ensure a consistent interface across different implementations. By defining an abstract base class, you're essentially setting a contract for what functionalities a set of classes should have.</p><p>An example of a abstract class is shown below</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist129884163\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-abstract_class_example-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;abstract_class_example.py\&quot;>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>ABC</span>, <span class=pl-s1>abstractmethod</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>Animal</span>(<span class=pl-v>ABC</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>make_sound</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Each subclass must implement a method to make a specific animal sound.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>move</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Each subclass must implement a method to define how the animal moves.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>Dog</span>(<span class=pl-v>Animal</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>make_sound</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>&amp;quot;Bark&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># The &amp;#39;move&amp;#39; method is intentionally not implemented to demonstrate the error</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>Fish</span>(<span class=pl-v>Animal</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>make_sound</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>&amp;quot;Blub&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    </td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>move</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>&amp;quot;Swims&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Try to instantiate classes and use methods</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>if</span> <span class=pl-s1>__name__</span> <span class=pl-c1>==</span> <span class=pl-s>&amp;quot;__main__&amp;quot;</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>try</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>animal</span> <span class=pl-c1>=</span> <span class=pl-v>Animal</span>()  <span class=pl-c># This will raise an error because Animal is abstract</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>except</span> <span class=pl-v>TypeError</span> <span class=pl-k>as</span> <span class=pl-s1>e</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;Error:&amp;quot;</span>, <span class=pl-s1>e</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>try</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>dog</span> <span class=pl-c1>=</span> <span class=pl-v>Dog</span>()  <span class=pl-c># This will also raise an error because it does not implement all abstract methods</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>except</span> <span class=pl-v>TypeError</span> <span class=pl-k>as</span> <span class=pl-s1>e</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;Error:&amp;quot;</span>, <span class=pl-s1>e</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>fish</span> <span class=pl-c1>=</span> <span class=pl-v>Fish</span>()  <span class=pl-c># This will work fine</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;Fish:&amp;quot;</span>, <span class=pl-s1>fish</span>.<span class=pl-en>make_sound</span>(), <span class=pl-s>&amp;quot;and&amp;quot;</span>, <span class=pl-s1>fish</span>.<span class=pl-en>move</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_class_example-py-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-abstract_class_example-py-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Dog and Animal instantiation errors are shown in the output</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/08641bc1b93c7a03855f3aa064f5f8f7/raw/c9a2b3861178d0e7481ec59ea1e3c1f4f6a956d6/abstract_class_example.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/08641bc1b93c7a03855f3aa064f5f8f7#file-abstract_class_example-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          abstract_class_example.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-1831e7b47678.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-1831e7b47678.css"><div id="gist129884163" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-abstract_class_example-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="abstract_class_example.py">
        <tbody><tr>
          <td id="file-abstract_class_example-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-abstract_class_example-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">ABC</span>, <span class="pl-s1">abstractmethod</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-abstract_class_example-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-abstract_class_example-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">Animal</span>(<span class="pl-v">ABC</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-abstract_class_example-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-abstract_class_example-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">make_sound</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-abstract_class_example-py-LC6" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Each subclass must implement a method to make a specific animal sound."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-abstract_class_example-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-abstract_class_example-py-LC8" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-abstract_class_example-py-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-abstract_class_example-py-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">move</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-abstract_class_example-py-LC11" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Each subclass must implement a method to define how the animal moves."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-abstract_class_example-py-LC12" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-abstract_class_example-py-LC13" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-abstract_class_example-py-LC14" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">Dog</span>(<span class="pl-v">Animal</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-abstract_class_example-py-LC15" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">make_sound</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-abstract_class_example-py-LC16" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">"Bark"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-abstract_class_example-py-LC17" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-abstract_class_example-py-LC18" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># The 'move' method is intentionally not implemented to demonstrate the error</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-abstract_class_example-py-LC19" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-abstract_class_example-py-LC20" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">Fish</span>(<span class="pl-v">Animal</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-abstract_class_example-py-LC21" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">make_sound</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-abstract_class_example-py-LC22" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">"Blub"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-abstract_class_example-py-LC23" class="blob-code blob-code-inner js-file-line">    </td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-abstract_class_example-py-LC24" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">move</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-abstract_class_example-py-LC25" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">"Swims"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-abstract_class_example-py-LC26" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-abstract_class_example-py-LC27" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Try to instantiate classes and use methods</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-abstract_class_example-py-LC28" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-abstract_class_example-py-LC29" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">try</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-abstract_class_example-py-LC30" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">animal</span> <span class="pl-c1">=</span> <span class="pl-v">Animal</span>()  <span class="pl-c"># This will raise an error because Animal is abstract</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-abstract_class_example-py-LC31" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">except</span> <span class="pl-v">TypeError</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-abstract_class_example-py-LC32" class="blob-code blob-code-inner js-file-line">        <span class="pl-en">print</span>(<span class="pl-s">"Error:"</span>, <span class="pl-s1">e</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-abstract_class_example-py-LC33" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-abstract_class_example-py-LC34" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">try</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-abstract_class_example-py-LC35" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">dog</span> <span class="pl-c1">=</span> <span class="pl-v">Dog</span>()  <span class="pl-c"># This will also raise an error because it does not implement all abstract methods</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-abstract_class_example-py-LC36" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">except</span> <span class="pl-v">TypeError</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-abstract_class_example-py-LC37" class="blob-code blob-code-inner js-file-line">        <span class="pl-en">print</span>(<span class="pl-s">"Error:"</span>, <span class="pl-s1">e</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-abstract_class_example-py-LC38" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-abstract_class_example-py-LC39" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">fish</span> <span class="pl-c1">=</span> <span class="pl-v">Fish</span>()  <span class="pl-c"># This will work fine</span></td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-abstract_class_example-py-LC40" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-abstract_class_example-py-LC41" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">"Fish:"</span>, <span class="pl-s1">fish</span>.<span class="pl-en">make_sound</span>(), <span class="pl-s">"and"</span>, <span class="pl-s1">fish</span>.<span class="pl-en">move</span>())</td>
        </tr>
        <tr>
          <td id="file-abstract_class_example-py-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-abstract_class_example-py-LC42" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Dog and Animal instantiation errors are shown in the output</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/08641bc1b93c7a03855f3aa064f5f8f7/raw/c9a2b3861178d0e7481ec59ea1e3c1f4f6a956d6/abstract_class_example.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/08641bc1b93c7a03855f3aa064f5f8f7#file-abstract_class_example-py" class="Link--inTextBlock">
          abstract_class_example.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>In this simple example, we have a abstract base class Animal, which prescribes any subclass needs to implement a make_sound and move method. We cannot instantiate the Animal class itself directly as it&#8217;s used for templating. We also cannot instantiate the subclasses if they don&#8217;t implement the required methods. So, abstract base classes are a way of enforcing a contract for a specific set of classes. That is, it defines a set of prescriptions of how a class should be constructed and typically resides in the first most basal layers in a code base.</p><h2>Abstract Base Class Methods</h2><p>The ABC library in python is very small at <a href="https://github.com/python/cpython/blob/3.12/Lib/abc.py">&lt;200 lines of code as of today</a>. As such there&#8217;s really only a few simple components from this library that will cover 95% of use cases. The <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a></strong> decorator is the main interface to create abstract definitions. It can be used in conjunction with a few types of methods in a class:</p><h3>Abstract classmethod</h3><p>A class method is a class function that can be used without instantiating a class object first. Creating a class object can be done by combining the <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a></strong> with a <strong><a href="https://docs.python.org/3/library/functions.html#classmethod">@classmethod</a></strong> decorator like so:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist129884857\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-abstract_classmethod-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;abstract_classmethod.py\&quot;>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>ABC</span>, <span class=pl-s1>abstractmethod</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DataSource</span>(<span class=pl-v>ABC</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>classmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>configure</span>(<span class=pl-s1>cls</span>, <span class=pl-s1>config</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s>        Configures database connection parameters. Each subclass must implement this</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s>        method based on its database type specifications.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s>        &amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>execute_query</span>(<span class=pl-s1>self</span>, <span class=pl-s1>query</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s>        Executes a given query on the database instance. Implementation will vary</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s>        depending on the database type.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s>        &amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>SQLDataSource</span>(<span class=pl-v>DataSource</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>connection_params</span> <span class=pl-c1>=</span> {}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>classmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>configure</span>(<span class=pl-s1>cls</span>, <span class=pl-s1>config</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>cls</span>.<span class=pl-s1>connection_params</span> <span class=pl-c1>=</span> <span class=pl-s1>config</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Configured SQL database with parameters: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>cls</span>.<span class=pl-s1>connection_params</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>execute_query</span>(<span class=pl-s1>self</span>, <span class=pl-s1>query</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Executing SQL query: &amp;#39;<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>query</span><span class=pl-kos>}</span></span>&amp;#39; with parameters <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>connection_params</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>NoSQLDataSource</span>(<span class=pl-v>DataSource</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>environment_settings</span> <span class=pl-c1>=</span> {}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>classmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>configure</span>(<span class=pl-s1>cls</span>, <span class=pl-s1>config</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>cls</span>.<span class=pl-s1>environment_settings</span> <span class=pl-c1>=</span> <span class=pl-s1>config</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Configured NoSQL database with settings: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>cls</span>.<span class=pl-s1>environment_settings</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>execute_query</span>(<span class=pl-s1>self</span>, <span class=pl-s1>query</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Executing NoSQL query: &amp;#39;<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>query</span><span class=pl-kos>}</span></span>&amp;#39; with settings <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>environment_settings</span><span class=pl-kos>}</span></span>&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L43\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;43\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC43\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage of class methods and instance methods</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L44\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;44\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC44\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>sql_config</span> <span class=pl-c1>=</span> {<span class=pl-s>&amp;#39;host&amp;#39;</span>: <span class=pl-s>&amp;#39;localhost&amp;#39;</span>, <span class=pl-s>&amp;#39;port&amp;#39;</span>: <span class=pl-c1>5432</span>}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L45\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;45\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC45\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-v>SQLDataSource</span>.<span class=pl-en>configure</span>(<span class=pl-s1>sql_config</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L46\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;46\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC46\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L47\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;47\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC47\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>nosql_config</span> <span class=pl-c1>=</span> {<span class=pl-s>&amp;#39;environment&amp;#39;</span>: <span class=pl-s>&amp;#39;cloud&amp;#39;</span>, <span class=pl-s>&amp;#39;replication&amp;#39;</span>: <span class=pl-s>&amp;#39;enabled&amp;#39;</span>}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L48\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;48\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC48\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-v>NoSQLDataSource</span>.<span class=pl-en>configure</span>(<span class=pl-s1>nosql_config</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L49\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;49\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC49\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L50\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;50\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC50\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>sql_data_source</span> <span class=pl-c1>=</span> <span class=pl-v>SQLDataSource</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L51\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;51\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC51\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-s1>sql_data_source</span>.<span class=pl-en>execute_query</span>(<span class=pl-s>&amp;quot;SELECT * FROM users&amp;quot;</span>))</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L52\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;52\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC52\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L53\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;53\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC53\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>nosql_data_source</span> <span class=pl-c1>=</span> <span class=pl-v>NoSQLDataSource</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_classmethod-py-L54\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;54\&quot;></td>\n          <td id=\&quot;file-abstract_classmethod-py-LC54\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-en>print</span>(<span class=pl-s1>nosql_data_source</span>.<span class=pl-en>execute_query</span>(<span class=pl-s>&amp;quot;{find: &amp;#39;users&amp;#39;, filter: {active: true}}&amp;quot;</span>))</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4/raw/8eb1294fe8036f1821470b3f87c7ab5ed8bc4cec/abstract_classmethod.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          abstract_classmethod.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-1831e7b47678.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-1831e7b47678.css"><div id="gist129884857" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-abstract_classmethod-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="abstract_classmethod.py">
        <tbody><tr>
          <td id="file-abstract_classmethod-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-abstract_classmethod-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">ABC</span>, <span class="pl-s1">abstractmethod</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-abstract_classmethod-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-abstract_classmethod-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DataSource</span>(<span class="pl-v">ABC</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-abstract_classmethod-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">classmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-abstract_classmethod-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-abstract_classmethod-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">configure</span>(<span class="pl-s1">cls</span>, <span class="pl-s1">config</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-abstract_classmethod-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-abstract_classmethod-py-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-s">        Configures database connection parameters. Each subclass must implement this</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-abstract_classmethod-py-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-s">        method based on its database type specifications.</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-abstract_classmethod-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-s">        """</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-abstract_classmethod-py-LC11" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-abstract_classmethod-py-LC12" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-abstract_classmethod-py-LC13" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-abstract_classmethod-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">execute_query</span>(<span class="pl-s1">self</span>, <span class="pl-s1">query</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-abstract_classmethod-py-LC15" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-abstract_classmethod-py-LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-s">        Executes a given query on the database instance. Implementation will vary</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-abstract_classmethod-py-LC17" class="blob-code blob-code-inner js-file-line"><span class="pl-s">        depending on the database type.</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-abstract_classmethod-py-LC18" class="blob-code blob-code-inner js-file-line"><span class="pl-s">        """</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-abstract_classmethod-py-LC19" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-abstract_classmethod-py-LC20" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-abstract_classmethod-py-LC21" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">SQLDataSource</span>(<span class="pl-v">DataSource</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-abstract_classmethod-py-LC22" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">connection_params</span> <span class="pl-c1">=</span> {}</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-abstract_classmethod-py-LC23" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-abstract_classmethod-py-LC24" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">classmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-abstract_classmethod-py-LC25" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">configure</span>(<span class="pl-s1">cls</span>, <span class="pl-s1">config</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-abstract_classmethod-py-LC26" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">cls</span>.<span class="pl-s1">connection_params</span> <span class="pl-c1">=</span> <span class="pl-s1">config</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-abstract_classmethod-py-LC27" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Configured SQL database with parameters: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">cls</span>.<span class="pl-s1">connection_params</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-abstract_classmethod-py-LC28" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-abstract_classmethod-py-LC29" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">execute_query</span>(<span class="pl-s1">self</span>, <span class="pl-s1">query</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-abstract_classmethod-py-LC30" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Executing SQL query: '<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">query</span><span class="pl-kos">}</span></span>' with parameters <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">connection_params</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-abstract_classmethod-py-LC31" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-abstract_classmethod-py-LC32" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">NoSQLDataSource</span>(<span class="pl-v">DataSource</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-abstract_classmethod-py-LC33" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">environment_settings</span> <span class="pl-c1">=</span> {}</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-abstract_classmethod-py-LC34" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-abstract_classmethod-py-LC35" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">classmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-abstract_classmethod-py-LC36" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">configure</span>(<span class="pl-s1">cls</span>, <span class="pl-s1">config</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-abstract_classmethod-py-LC37" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">cls</span>.<span class="pl-s1">environment_settings</span> <span class="pl-c1">=</span> <span class="pl-s1">config</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-abstract_classmethod-py-LC38" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Configured NoSQL database with settings: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">cls</span>.<span class="pl-s1">environment_settings</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-abstract_classmethod-py-LC39" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-abstract_classmethod-py-LC40" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">execute_query</span>(<span class="pl-s1">self</span>, <span class="pl-s1">query</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-abstract_classmethod-py-LC41" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Executing NoSQL query: '<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">query</span><span class="pl-kos">}</span></span>' with settings <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">environment_settings</span><span class="pl-kos">}</span></span>"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-abstract_classmethod-py-LC42" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L43" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="43"></td>
          <td id="file-abstract_classmethod-py-LC43" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage of class methods and instance methods</span></td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L44" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="44"></td>
          <td id="file-abstract_classmethod-py-LC44" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">sql_config</span> <span class="pl-c1">=</span> {<span class="pl-s">'host'</span>: <span class="pl-s">'localhost'</span>, <span class="pl-s">'port'</span>: <span class="pl-c1">5432</span>}</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L45" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="45"></td>
          <td id="file-abstract_classmethod-py-LC45" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-v">SQLDataSource</span>.<span class="pl-en">configure</span>(<span class="pl-s1">sql_config</span>))</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L46" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="46"></td>
          <td id="file-abstract_classmethod-py-LC46" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L47" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="47"></td>
          <td id="file-abstract_classmethod-py-LC47" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">nosql_config</span> <span class="pl-c1">=</span> {<span class="pl-s">'environment'</span>: <span class="pl-s">'cloud'</span>, <span class="pl-s">'replication'</span>: <span class="pl-s">'enabled'</span>}</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L48" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="48"></td>
          <td id="file-abstract_classmethod-py-LC48" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-v">NoSQLDataSource</span>.<span class="pl-en">configure</span>(<span class="pl-s1">nosql_config</span>))</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L49" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="49"></td>
          <td id="file-abstract_classmethod-py-LC49" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L50" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="50"></td>
          <td id="file-abstract_classmethod-py-LC50" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">sql_data_source</span> <span class="pl-c1">=</span> <span class="pl-v">SQLDataSource</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L51" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="51"></td>
          <td id="file-abstract_classmethod-py-LC51" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-s1">sql_data_source</span>.<span class="pl-en">execute_query</span>(<span class="pl-s">"SELECT * FROM users"</span>))</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L52" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="52"></td>
          <td id="file-abstract_classmethod-py-LC52" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L53" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="53"></td>
          <td id="file-abstract_classmethod-py-LC53" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">nosql_data_source</span> <span class="pl-c1">=</span> <span class="pl-v">NoSQLDataSource</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_classmethod-py-L54" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="54"></td>
          <td id="file-abstract_classmethod-py-LC54" class="blob-code blob-code-inner js-file-line"><span class="pl-en">print</span>(<span class="pl-s1">nosql_data_source</span>.<span class="pl-en">execute_query</span>(<span class="pl-s">"{find: 'users', filter: {active: true}}"</span>))</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4/raw/8eb1294fe8036f1821470b3f87c7ab5ed8bc4cec/abstract_classmethod.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py" class="Link--inTextBlock">
          abstract_classmethod.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>In this example we create an abstract base class for<a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L3"> </a><strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L3">DataSource</a> </strong>with functions <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L6">configure</a></strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L6"> </a>and <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L14">execute_query</a></strong>. The subclasses <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L21">SQLDataSource</a></strong> and <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L32">NoSQLDataSource</a></strong> are inheriting from <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L3">DataSource</a> </strong>and they will need to implement these methods now. Notice the difference between a <strong><a href="https://docs.python.org/3/library/functions.html#classmethod">classmethod</a></strong> and an <strong><a href="https://docs.python.org/3/reference/datamodel.html#instance-methods">instance method</a></strong> (&#8220;regular method&#8221;). The <strong><a href="https://docs.python.org/3/library/functions.html#classmethod">classmethod</a></strong> does not need an instance of the class, but has access to (default) attributes of the class through <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L6">cls</a></strong>, whereas an <strong><a href="https://docs.python.org/3/reference/datamodel.html#instance-methods">instance method</a></strong> is more tightly bound to that instance of the class and can access the attributes of the current instance through <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L14">self</a></strong>. A <strong><a href="https://docs.python.org/3/library/functions.html#classmethod">classmethod</a></strong> then, is for example  useful when dealing with more complicated shared setup.</p><h3>Abstract staticmethod</h3><p>A <strong><a href="https://docs.python.org/3/reference/datamodel.html#static-method-objects">staticmethod</a></strong> is essentially a regular python function that is tied to the namespace of a class. This method can be called without a class instance (unlike regular functions added to a class) and it does not have access to the internal properties of the class (so no access to <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L14">self</a></strong> or <strong><a href="https://gist.github.com/2tony2/dd700c8a190c3d7733bc12b226958ed4#file-abstract_classmethod-py-L6">cls</a></strong>). Similarly to an abstract classmethod, you can create these by combining the <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a></strong> with a <strong><a href="https://docs.python.org/3/library/functions.html#staticmethod">@staticmethod</a></strong> decorator like so:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist129921209\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-abstract_static_method-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;abstract_static_method.py\&quot;>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>ABC</span>, <span class=pl-s1>abstractmethod</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DataFormatter</span>(<span class=pl-v>ABC</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>staticmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>format_data</span>(<span class=pl-s1>data</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Define a standard way to format data.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>JSONFormatter</span>(<span class=pl-v>DataFormatter</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>staticmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>format_data</span>(<span class=pl-s1>data</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Format data as JSON.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>import</span> <span class=pl-s1>json</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s1>json</span>.<span class=pl-en>dumps</span>(<span class=pl-s1>data</span>, <span class=pl-s1>ensure_ascii</span><span class=pl-c1>=</span><span class=pl-c1>False</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>CSVFormatter</span>(<span class=pl-v>DataFormatter</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>staticmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>format_data</span>(<span class=pl-s1>data</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Format data as CSV.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>import</span> <span class=pl-s1>csv</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>from</span> <span class=pl-s1>io</span> <span class=pl-k>import</span> <span class=pl-v>StringIO</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>output</span> <span class=pl-c1>=</span> <span class=pl-v>StringIO</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>writer</span> <span class=pl-c1>=</span> <span class=pl-s1>csv</span>.<span class=pl-v>DictWriter</span>(<span class=pl-s1>output</span>, <span class=pl-s1>fieldnames</span><span class=pl-c1>=</span><span class=pl-s1>data</span>[<span class=pl-c1>0</span>].<span class=pl-en>keys</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>writer</span>.<span class=pl-en>writeheader</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>writer</span>.<span class=pl-en>writerows</span>(<span class=pl-s1>data</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s1>output</span>.<span class=pl-en>getvalue</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage example</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>if</span> <span class=pl-s1>__name__</span> <span class=pl-c1>==</span> <span class=pl-s>&amp;quot;__main__&amp;quot;</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Example data</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>data_dict</span> <span class=pl-c1>=</span> {<span class=pl-s>&amp;quot;name&amp;quot;</span>: <span class=pl-s>&amp;quot;Alice&amp;quot;</span>, <span class=pl-s>&amp;quot;age&amp;quot;</span>: <span class=pl-c1>30</span>, <span class=pl-s>&amp;quot;city&amp;quot;</span>: <span class=pl-s>&amp;quot;New York&amp;quot;</span>}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>data_list</span> <span class=pl-c1>=</span> [</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        {<span class=pl-s>&amp;quot;name&amp;quot;</span>: <span class=pl-s>&amp;quot;Alice&amp;quot;</span>, <span class=pl-s>&amp;quot;age&amp;quot;</span>: <span class=pl-c1>30</span>, <span class=pl-s>&amp;quot;city&amp;quot;</span>: <span class=pl-s>&amp;quot;New York&amp;quot;</span>},</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        {<span class=pl-s>&amp;quot;name&amp;quot;</span>: <span class=pl-s>&amp;quot;Bob&amp;quot;</span>, <span class=pl-s>&amp;quot;age&amp;quot;</span>: <span class=pl-c1>25</span>, <span class=pl-s>&amp;quot;city&amp;quot;</span>: <span class=pl-s>&amp;quot;Los Angeles&amp;quot;</span>}</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    ]</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Format as JSON</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>json_data</span> <span class=pl-c1>=</span> <span class=pl-v>JSONFormatter</span>.<span class=pl-en>format_data</span>(<span class=pl-s1>data_dict</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;JSON Formatted Data:&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>json_data</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L43\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;43\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC43\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Format as CSV</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L44\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;44\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC44\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>csv_data</span> <span class=pl-c1>=</span> <span class=pl-v>CSVFormatter</span>.<span class=pl-en>format_data</span>(<span class=pl-s1>data_list</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L45\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;45\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC45\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;CSV Formatted Data:&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_static_method-py-L46\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;46\&quot;></td>\n          <td id=\&quot;file-abstract_static_method-py-LC46\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>csv_data</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/124d0d00a4a58c26288e4c1f4958cc57/raw/7ee29d609085503b9e0619be030e73e4c7ea39a4/abstract_static_method.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/124d0d00a4a58c26288e4c1f4958cc57#file-abstract_static_method-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          abstract_static_method.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-1831e7b47678.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-1831e7b47678.css"><div id="gist129921209" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-abstract_static_method-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="abstract_static_method.py">
        <tbody><tr>
          <td id="file-abstract_static_method-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-abstract_static_method-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">ABC</span>, <span class="pl-s1">abstractmethod</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-abstract_static_method-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-abstract_static_method-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DataFormatter</span>(<span class="pl-v">ABC</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-abstract_static_method-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">staticmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-abstract_static_method-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-abstract_static_method-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">format_data</span>(<span class="pl-s1">data</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-abstract_static_method-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Define a standard way to format data."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-abstract_static_method-py-LC8" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-abstract_static_method-py-LC9" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-abstract_static_method-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">JSONFormatter</span>(<span class="pl-v">DataFormatter</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-abstract_static_method-py-LC11" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">staticmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-abstract_static_method-py-LC12" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">format_data</span>(<span class="pl-s1">data</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-abstract_static_method-py-LC13" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Format data as JSON."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-abstract_static_method-py-LC14" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">import</span> <span class="pl-s1">json</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-abstract_static_method-py-LC15" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s1">json</span>.<span class="pl-en">dumps</span>(<span class="pl-s1">data</span>, <span class="pl-s1">ensure_ascii</span><span class="pl-c1">=</span><span class="pl-c1">False</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-abstract_static_method-py-LC16" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-abstract_static_method-py-LC17" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">CSVFormatter</span>(<span class="pl-v">DataFormatter</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-abstract_static_method-py-LC18" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">staticmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-abstract_static_method-py-LC19" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">format_data</span>(<span class="pl-s1">data</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-abstract_static_method-py-LC20" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Format data as CSV."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-abstract_static_method-py-LC21" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">import</span> <span class="pl-s1">csv</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-abstract_static_method-py-LC22" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">from</span> <span class="pl-s1">io</span> <span class="pl-k">import</span> <span class="pl-v">StringIO</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-abstract_static_method-py-LC23" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">output</span> <span class="pl-c1">=</span> <span class="pl-v">StringIO</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-abstract_static_method-py-LC24" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">writer</span> <span class="pl-c1">=</span> <span class="pl-s1">csv</span>.<span class="pl-v">DictWriter</span>(<span class="pl-s1">output</span>, <span class="pl-s1">fieldnames</span><span class="pl-c1">=</span><span class="pl-s1">data</span>[<span class="pl-c1">0</span>].<span class="pl-en">keys</span>())</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-abstract_static_method-py-LC25" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">writer</span>.<span class="pl-en">writeheader</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-abstract_static_method-py-LC26" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">writer</span>.<span class="pl-en">writerows</span>(<span class="pl-s1">data</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-abstract_static_method-py-LC27" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s1">output</span>.<span class="pl-en">getvalue</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-abstract_static_method-py-LC28" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-abstract_static_method-py-LC29" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage example</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-abstract_static_method-py-LC30" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-abstract_static_method-py-LC31" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Example data</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-abstract_static_method-py-LC32" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">data_dict</span> <span class="pl-c1">=</span> {<span class="pl-s">"name"</span>: <span class="pl-s">"Alice"</span>, <span class="pl-s">"age"</span>: <span class="pl-c1">30</span>, <span class="pl-s">"city"</span>: <span class="pl-s">"New York"</span>}</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-abstract_static_method-py-LC33" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">data_list</span> <span class="pl-c1">=</span> [</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-abstract_static_method-py-LC34" class="blob-code blob-code-inner js-file-line">        {<span class="pl-s">"name"</span>: <span class="pl-s">"Alice"</span>, <span class="pl-s">"age"</span>: <span class="pl-c1">30</span>, <span class="pl-s">"city"</span>: <span class="pl-s">"New York"</span>},</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-abstract_static_method-py-LC35" class="blob-code blob-code-inner js-file-line">        {<span class="pl-s">"name"</span>: <span class="pl-s">"Bob"</span>, <span class="pl-s">"age"</span>: <span class="pl-c1">25</span>, <span class="pl-s">"city"</span>: <span class="pl-s">"Los Angeles"</span>}</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-abstract_static_method-py-LC36" class="blob-code blob-code-inner js-file-line">    ]</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-abstract_static_method-py-LC37" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-abstract_static_method-py-LC38" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Format as JSON</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-abstract_static_method-py-LC39" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">json_data</span> <span class="pl-c1">=</span> <span class="pl-v">JSONFormatter</span>.<span class="pl-en">format_data</span>(<span class="pl-s1">data_dict</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-abstract_static_method-py-LC40" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">"JSON Formatted Data:"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-abstract_static_method-py-LC41" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">json_data</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-abstract_static_method-py-LC42" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L43" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="43"></td>
          <td id="file-abstract_static_method-py-LC43" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Format as CSV</span></td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L44" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="44"></td>
          <td id="file-abstract_static_method-py-LC44" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">csv_data</span> <span class="pl-c1">=</span> <span class="pl-v">CSVFormatter</span>.<span class="pl-en">format_data</span>(<span class="pl-s1">data_list</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L45" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="45"></td>
          <td id="file-abstract_static_method-py-LC45" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">"CSV Formatted Data:"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_static_method-py-L46" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="46"></td>
          <td id="file-abstract_static_method-py-LC46" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">csv_data</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/124d0d00a4a58c26288e4c1f4958cc57/raw/7ee29d609085503b9e0619be030e73e4c7ea39a4/abstract_static_method.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/124d0d00a4a58c26288e4c1f4958cc57#file-abstract_static_method-py" class="Link--inTextBlock">
          abstract_static_method.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>Static methods are great for utility classes that keep a set of functions for similar purposes or processes that can be used across functions and classes that are independent of each other. </p><h3>Abstract property method</h3><p>A property is a class function that is used to create a attribute for the class. Again, creating an abstract property can be done through combining <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a> </strong>with a <strong><a href="https://docs.python.org/3/library/functions.html#property">@property</a></strong> decorator like so:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist129921273\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-abstract_property-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;abstract_property.py\&quot;>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>ABC</span>, <span class=pl-s1>abstractmethod</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DatabaseConfig</span>(<span class=pl-v>ABC</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>property</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>connection_string</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Define a standardized property to get a database connection string.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>ProductionDatabaseConfig</span>(<span class=pl-v>DatabaseConfig</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__init__</span>(<span class=pl-s1>self</span>, <span class=pl-s1>host</span>, <span class=pl-s1>database</span>, <span class=pl-s1>user</span>, <span class=pl-s1>password</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>host</span> <span class=pl-c1>=</span> <span class=pl-s1>host</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>database</span> <span class=pl-c1>=</span> <span class=pl-s1>database</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>user</span> <span class=pl-c1>=</span> <span class=pl-s1>user</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>password</span> <span class=pl-c1>=</span> <span class=pl-s1>password</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>property</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>connection_string</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Generate a connection string using production credentials.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Server=<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>host</span><span class=pl-kos>}</span></span>;Database=<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>database</span><span class=pl-kos>}</span></span>;User Id=<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>user</span><span class=pl-kos>}</span></span>;Password=<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>password</span><span class=pl-kos>}</span></span>;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>DevelopmentDatabaseConfig</span>(<span class=pl-v>DatabaseConfig</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>__init__</span>(<span class=pl-s1>self</span>, <span class=pl-s1>host</span>, <span class=pl-s1>database</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>host</span> <span class=pl-c1>=</span> <span class=pl-s1>host</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>self</span>.<span class=pl-s1>database</span> <span class=pl-c1>=</span> <span class=pl-s1>database</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>property</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>connection_string</span>(<span class=pl-s1>self</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Generate a connection string using development credentials with default user.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>return</span> <span class=pl-s>f&amp;quot;Server=<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>host</span><span class=pl-kos>}</span></span>;Database=<span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>self</span>.<span class=pl-s1>database</span><span class=pl-kos>}</span></span>;User Id=dev;Password=dev;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage example</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>if</span> <span class=pl-s1>__name__</span> <span class=pl-c1>==</span> <span class=pl-s>&amp;quot;__main__&amp;quot;</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Initialize configurations</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>prod_config</span> <span class=pl-c1>=</span> <span class=pl-v>ProductionDatabaseConfig</span>(<span class=pl-s>&amp;quot;prod-server&amp;quot;</span>, <span class=pl-s>&amp;quot;prod-db&amp;quot;</span>, <span class=pl-s>&amp;quot;admin&amp;quot;</span>, <span class=pl-s>&amp;quot;securepassword&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>dev_config</span> <span class=pl-c1>=</span> <span class=pl-v>DevelopmentDatabaseConfig</span>(<span class=pl-s>&amp;quot;dev-server&amp;quot;</span>, <span class=pl-s>&amp;quot;dev-db&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Print connection strings</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;Production Connection String:&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>prod_config</span>.<span class=pl-s1>connection_string</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;Development Connection String:&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_property-py-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-abstract_property-py-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>print</span>(<span class=pl-s1>dev_config</span>.<span class=pl-s1>connection_string</span>)</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/4c359bd5e034f58dfb72ebaa710c6cf6/raw/b282b4eb8524b8bc0af3c7f4cd91187b5bbecdf5/abstract_property.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/4c359bd5e034f58dfb72ebaa710c6cf6#file-abstract_property-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          abstract_property.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-1831e7b47678.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-1831e7b47678.css"><div id="gist129921273" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-abstract_property-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="abstract_property.py">
        <tbody><tr>
          <td id="file-abstract_property-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-abstract_property-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">ABC</span>, <span class="pl-s1">abstractmethod</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-abstract_property-py-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-abstract_property-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DatabaseConfig</span>(<span class="pl-v">ABC</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-abstract_property-py-LC4" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">property</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-abstract_property-py-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-abstract_property-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">connection_string</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-abstract_property-py-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Define a standardized property to get a database connection string."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-abstract_property-py-LC8" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-abstract_property-py-LC9" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-abstract_property-py-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">ProductionDatabaseConfig</span>(<span class="pl-v">DatabaseConfig</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-abstract_property-py-LC11" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">host</span>, <span class="pl-s1">database</span>, <span class="pl-s1">user</span>, <span class="pl-s1">password</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-abstract_property-py-LC12" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">host</span> <span class="pl-c1">=</span> <span class="pl-s1">host</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-abstract_property-py-LC13" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">database</span> <span class="pl-c1">=</span> <span class="pl-s1">database</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-abstract_property-py-LC14" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">user</span> <span class="pl-c1">=</span> <span class="pl-s1">user</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-abstract_property-py-LC15" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">password</span> <span class="pl-c1">=</span> <span class="pl-s1">password</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-abstract_property-py-LC16" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-abstract_property-py-LC17" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">property</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-abstract_property-py-LC18" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">connection_string</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-abstract_property-py-LC19" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Generate a connection string using production credentials."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-abstract_property-py-LC20" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Server=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">host</span><span class="pl-kos">}</span></span>;Database=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">database</span><span class="pl-kos">}</span></span>;User Id=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">user</span><span class="pl-kos">}</span></span>;Password=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">password</span><span class="pl-kos">}</span></span>;"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-abstract_property-py-LC21" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-abstract_property-py-LC22" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">DevelopmentDatabaseConfig</span>(<span class="pl-v">DatabaseConfig</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-abstract_property-py-LC23" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">host</span>, <span class="pl-s1">database</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-abstract_property-py-LC24" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">host</span> <span class="pl-c1">=</span> <span class="pl-s1">host</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-abstract_property-py-LC25" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">self</span>.<span class="pl-s1">database</span> <span class="pl-c1">=</span> <span class="pl-s1">database</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-abstract_property-py-LC26" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-abstract_property-py-LC27" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">property</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-abstract_property-py-LC28" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">connection_string</span>(<span class="pl-s1">self</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-abstract_property-py-LC29" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Generate a connection string using development credentials with default user."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-abstract_property-py-LC30" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> <span class="pl-s">f"Server=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">host</span><span class="pl-kos">}</span></span>;Database=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">self</span>.<span class="pl-s1">database</span><span class="pl-kos">}</span></span>;User Id=dev;Password=dev;"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-abstract_property-py-LC31" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-abstract_property-py-LC32" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage example</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-abstract_property-py-LC33" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-abstract_property-py-LC34" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Initialize configurations</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-abstract_property-py-LC35" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">prod_config</span> <span class="pl-c1">=</span> <span class="pl-v">ProductionDatabaseConfig</span>(<span class="pl-s">"prod-server"</span>, <span class="pl-s">"prod-db"</span>, <span class="pl-s">"admin"</span>, <span class="pl-s">"securepassword"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-abstract_property-py-LC36" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">dev_config</span> <span class="pl-c1">=</span> <span class="pl-v">DevelopmentDatabaseConfig</span>(<span class="pl-s">"dev-server"</span>, <span class="pl-s">"dev-db"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-abstract_property-py-LC37" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-abstract_property-py-LC38" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Print connection strings</span></td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-abstract_property-py-LC39" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">"Production Connection String:"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-abstract_property-py-LC40" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">prod_config</span>.<span class="pl-s1">connection_string</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-abstract_property-py-LC41" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s">"Development Connection String:"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_property-py-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-abstract_property-py-LC42" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">print</span>(<span class="pl-s1">dev_config</span>.<span class="pl-s1">connection_string</span>)</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/4c359bd5e034f58dfb72ebaa710c6cf6/raw/b282b4eb8524b8bc0af3c7f4cd91187b5bbecdf5/abstract_property.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/4c359bd5e034f58dfb72ebaa710c6cf6#file-abstract_property-py" class="Link--inTextBlock">
          abstract_property.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>Properties are useful when the definition of a class attribute is dependent on values of other attributes within the class or when this attribute requires a more elaborate calculation to set. Note that properties are separate entities from class attributes.</p><h2>Using <code>@abstractmethod</code> with other function constructs</h2><p>As you have probably noticed by now, all of the above methods follow a very similar structure where any function can be decorated with  <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a></strong> to make it abstract. This is very flexible and allows for a lot of different types of flexible definitions. Again, check the source code, it is pretty straightforward. A few more advanced examples of types of functions that  <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a></strong> can be applied to with useful purposes in data engineering are shown below.</p><h2>Abstract Context Manager</h2><p>Context managers in Python provide a convenient way to allocate and release resources precisely when needed. By using the <strong><a href="https://docs.python.org/3/reference/compound_stmts.html#the-with-statement">with</a></strong> statement, context managers ensure that resources are automatically managed (such as opening and closing files, or acquiring and releasing locks) without needing explicit cleanup code. This is useful for a few different types of operations:</p><ul><li><p>Handling files</p></li><li><p>Handling database connections</p></li><li><p>Asynchronous and Concurrent operations</p></li></ul><p>The <strong><a href="https://docs.python.org/3/library/contextlib.html#module-contextlib">contextlib</a></strong> library in python provides excellent construct to create your own context managers and combining this with <strong><a href="https://docs.python.org/3/library/abc.html#abc.abstractmethod">@abstractmethod</a></strong> allows to create a data model for code covering these very common use cases.</p><p>For example, let&#8217;s say we want to define a set of file handling context managers that are specifically written for encrypting data. We want to make sure that if our encryption fails, we still close any file we opened. We may also want to have custom exception behavior. This may look something like this:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist129921374\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-abstract_context_manager-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;abstract_context_manager.py\&quot;>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>ABC</span>, <span class=pl-s1>abstractmethod</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>contextlib</span> <span class=pl-k>import</span> <span class=pl-s1>contextmanager</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>cryptography</span>.<span class=pl-s1>fernet</span> <span class=pl-k>import</span> <span class=pl-v>Fernet</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>CryptoFileManager</span>(<span class=pl-v>ABC</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>contextmanager</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>secure_file_handler</span>(<span class=pl-s1>self</span>, <span class=pl-s1>path</span>, <span class=pl-s1>mode</span>, <span class=pl-s1>key</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;A context manager for encrypting or decrypting files.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>FileEncryptor</span>(<span class=pl-v>CryptoFileManager</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>contextmanager</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>secure_file_handler</span>(<span class=pl-s1>self</span>, <span class=pl-s1>path</span>, <span class=pl-s1>mode</span>, <span class=pl-s1>key</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Encrypts file content on write.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>try</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>cipher</span> <span class=pl-c1>=</span> <span class=pl-v>Fernet</span>(<span class=pl-s1>key</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>with</span> <span class=pl-en>open</span>(<span class=pl-s1>path</span>, <span class=pl-s1>mode</span>) <span class=pl-k>as</span> <span class=pl-s1>file</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-s1>data</span> <span class=pl-c1>=</span> <span class=pl-s1>file</span>.<span class=pl-en>read</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-s1>encrypted_data</span> <span class=pl-c1>=</span> <span class=pl-s1>cipher</span>.<span class=pl-en>encrypt</span>(<span class=pl-s1>data</span>.<span class=pl-en>encode</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-s1>file</span>.<span class=pl-en>seek</span>(<span class=pl-c1>0</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-s1>file</span>.<span class=pl-en>write</span>(<span class=pl-s1>encrypted_data</span>.<span class=pl-en>decode</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-k>yield</span> <span class=pl-s1>file</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>except</span> <span class=pl-v>Exception</span> <span class=pl-k>as</span> <span class=pl-s1>e</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;Failed to encrypt file: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>e</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>finally</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;File encryption completed and file <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>path</span><span class=pl-kos>}</span></span> has been closed.&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>FileDecryptor</span>(<span class=pl-v>CryptoFileManager</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>contextmanager</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>def</span> <span class=pl-en>secure_file_handler</span>(<span class=pl-s1>self</span>, <span class=pl-s1>path</span>, <span class=pl-s1>mode</span>, <span class=pl-s1>key</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;Decrypts file content on read.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>file</span> <span class=pl-c1>=</span> <span class=pl-c1>None</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>try</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>cipher</span> <span class=pl-c1>=</span> <span class=pl-v>Fernet</span>(<span class=pl-s1>key</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>file</span> <span class=pl-c1>=</span> <span class=pl-en>open</span>(<span class=pl-s1>path</span>, <span class=pl-s1>mode</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>encrypted_data</span> <span class=pl-c1>=</span> <span class=pl-s1>file</span>.<span class=pl-en>read</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>decrypted_data</span> <span class=pl-c1>=</span> <span class=pl-s1>cipher</span>.<span class=pl-en>decrypt</span>(<span class=pl-s1>encrypted_data</span>.<span class=pl-en>encode</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>file</span>.<span class=pl-en>seek</span>(<span class=pl-c1>0</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>file</span>.<span class=pl-en>write</span>(<span class=pl-s1>decrypted_data</span>.<span class=pl-en>decode</span>())</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>file</span>.<span class=pl-en>seek</span>(<span class=pl-c1>0</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>yield</span> <span class=pl-s1>file</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L43\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;43\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC43\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>except</span> <span class=pl-v>Exception</span> <span class=pl-k>as</span> <span class=pl-s1>e</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L44\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;44\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC44\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;Failed to decrypt file: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>e</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L45\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;45\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC45\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>finally</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L46\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;46\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC46\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>if</span> <span class=pl-s1>file</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L47\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;47\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC47\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-s1>file</span>.<span class=pl-en>close</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L48\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;48\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC48\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;File decryption completed and file <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>path</span><span class=pl-kos>}</span></span> has been closed.&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L49\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;49\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC49\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L50\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;50\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC50\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Example usage</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L51\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;51\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC51\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-s1>key</span> <span class=pl-c1>=</span> <span class=pl-v>Fernet</span>.<span class=pl-en>generate_key</span>()  <span class=pl-c># Normally you would store and retrieve this securely</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L52\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;52\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC52\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>if</span> <span class=pl-s1>__name__</span> <span class=pl-c1>==</span> <span class=pl-s>&amp;quot;__main__&amp;quot;</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L53\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;53\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC53\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>encryptor</span> <span class=pl-c1>=</span> <span class=pl-v>FileEncryptor</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L54\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;54\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC54\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>decryptor</span> <span class=pl-c1>=</span> <span class=pl-v>FileDecryptor</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L55\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;55\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC55\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Encrypt data</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L56\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;56\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC56\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>with</span> <span class=pl-s1>encryptor</span>.<span class=pl-en>secure_file_handler</span>(<span class=pl-s>&amp;#39;testfile.txt&amp;#39;</span>, <span class=pl-s>&amp;#39;w+&amp;#39;</span>, <span class=pl-s1>key</span>) <span class=pl-k>as</span> <span class=pl-s1>file</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L57\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;57\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC57\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>file</span>.<span class=pl-en>write</span>(<span class=pl-s>&amp;quot;Sensitive data that needs encryption.&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L58\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;58\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC58\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-c># Decrypt data</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L59\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;59\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC59\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>with</span> <span class=pl-s1>decryptor</span>.<span class=pl-en>secure_file_handler</span>(<span class=pl-s>&amp;#39;testfile.txt&amp;#39;</span>, <span class=pl-s>&amp;#39;r+&amp;#39;</span>, <span class=pl-s1>key</span>) <span class=pl-k>as</span> <span class=pl-s1>file</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_context_manager-py-L60\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;60\&quot;></td>\n          <td id=\&quot;file-abstract_context_manager-py-LC60\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-en>print</span>(<span class=pl-s>&amp;quot;Decrypted content:&amp;quot;</span>, <span class=pl-s1>file</span>.<span class=pl-en>read</span>())</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/a9ad9c3014703cf00579c0c5a71735a8/raw/8e90c98f7da33042fe84a4b0c7db9f4eb48848a8/abstract_context_manager.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/a9ad9c3014703cf00579c0c5a71735a8#file-abstract_context_manager-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          abstract_context_manager.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-1831e7b47678.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-1831e7b47678.css"><div id="gist129921374" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-abstract_context_manager-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="abstract_context_manager.py">
        <tbody><tr>
          <td id="file-abstract_context_manager-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-abstract_context_manager-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">ABC</span>, <span class="pl-s1">abstractmethod</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-abstract_context_manager-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">contextlib</span> <span class="pl-k">import</span> <span class="pl-s1">contextmanager</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-abstract_context_manager-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">cryptography</span>.<span class="pl-s1">fernet</span> <span class="pl-k">import</span> <span class="pl-v">Fernet</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-abstract_context_manager-py-LC4" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-abstract_context_manager-py-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">CryptoFileManager</span>(<span class="pl-v">ABC</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-abstract_context_manager-py-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-abstract_context_manager-py-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">contextmanager</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-abstract_context_manager-py-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">secure_file_handler</span>(<span class="pl-s1">self</span>, <span class="pl-s1">path</span>, <span class="pl-s1">mode</span>, <span class="pl-s1">key</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-abstract_context_manager-py-LC9" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""A context manager for encrypting or decrypting files."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-abstract_context_manager-py-LC10" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-abstract_context_manager-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-abstract_context_manager-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">FileEncryptor</span>(<span class="pl-v">CryptoFileManager</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-abstract_context_manager-py-LC13" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">contextmanager</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-abstract_context_manager-py-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">secure_file_handler</span>(<span class="pl-s1">self</span>, <span class="pl-s1">path</span>, <span class="pl-s1">mode</span>, <span class="pl-s1">key</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-abstract_context_manager-py-LC15" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Encrypts file content on write."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-abstract_context_manager-py-LC16" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">try</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-abstract_context_manager-py-LC17" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">cipher</span> <span class="pl-c1">=</span> <span class="pl-v">Fernet</span>(<span class="pl-s1">key</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-abstract_context_manager-py-LC18" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">with</span> <span class="pl-en">open</span>(<span class="pl-s1">path</span>, <span class="pl-s1">mode</span>) <span class="pl-k">as</span> <span class="pl-s1">file</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-abstract_context_manager-py-LC19" class="blob-code blob-code-inner js-file-line">                <span class="pl-s1">data</span> <span class="pl-c1">=</span> <span class="pl-s1">file</span>.<span class="pl-en">read</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-abstract_context_manager-py-LC20" class="blob-code blob-code-inner js-file-line">                <span class="pl-s1">encrypted_data</span> <span class="pl-c1">=</span> <span class="pl-s1">cipher</span>.<span class="pl-en">encrypt</span>(<span class="pl-s1">data</span>.<span class="pl-en">encode</span>())</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-abstract_context_manager-py-LC21" class="blob-code blob-code-inner js-file-line">                <span class="pl-s1">file</span>.<span class="pl-en">seek</span>(<span class="pl-c1">0</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-abstract_context_manager-py-LC22" class="blob-code blob-code-inner js-file-line">                <span class="pl-s1">file</span>.<span class="pl-en">write</span>(<span class="pl-s1">encrypted_data</span>.<span class="pl-en">decode</span>())</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-abstract_context_manager-py-LC23" class="blob-code blob-code-inner js-file-line">                <span class="pl-k">yield</span> <span class="pl-s1">file</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-abstract_context_manager-py-LC24" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-abstract_context_manager-py-LC25" class="blob-code blob-code-inner js-file-line">            <span class="pl-en">print</span>(<span class="pl-s">f"Failed to encrypt file: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-abstract_context_manager-py-LC26" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">finally</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-abstract_context_manager-py-LC27" class="blob-code blob-code-inner js-file-line">            <span class="pl-en">print</span>(<span class="pl-s">f"File encryption completed and file <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">path</span><span class="pl-kos">}</span></span> has been closed."</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-abstract_context_manager-py-LC28" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-abstract_context_manager-py-LC29" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">FileDecryptor</span>(<span class="pl-v">CryptoFileManager</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-abstract_context_manager-py-LC30" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">contextmanager</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-abstract_context_manager-py-LC31" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">def</span> <span class="pl-en">secure_file_handler</span>(<span class="pl-s1">self</span>, <span class="pl-s1">path</span>, <span class="pl-s1">mode</span>, <span class="pl-s1">key</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-abstract_context_manager-py-LC32" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""Decrypts file content on read."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-abstract_context_manager-py-LC33" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">file</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-abstract_context_manager-py-LC34" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">try</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-abstract_context_manager-py-LC35" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">cipher</span> <span class="pl-c1">=</span> <span class="pl-v">Fernet</span>(<span class="pl-s1">key</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-abstract_context_manager-py-LC36" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">file</span> <span class="pl-c1">=</span> <span class="pl-en">open</span>(<span class="pl-s1">path</span>, <span class="pl-s1">mode</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-abstract_context_manager-py-LC37" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">encrypted_data</span> <span class="pl-c1">=</span> <span class="pl-s1">file</span>.<span class="pl-en">read</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-abstract_context_manager-py-LC38" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">decrypted_data</span> <span class="pl-c1">=</span> <span class="pl-s1">cipher</span>.<span class="pl-en">decrypt</span>(<span class="pl-s1">encrypted_data</span>.<span class="pl-en">encode</span>())</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-abstract_context_manager-py-LC39" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">file</span>.<span class="pl-en">seek</span>(<span class="pl-c1">0</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-abstract_context_manager-py-LC40" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">file</span>.<span class="pl-en">write</span>(<span class="pl-s1">decrypted_data</span>.<span class="pl-en">decode</span>())</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-abstract_context_manager-py-LC41" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">file</span>.<span class="pl-en">seek</span>(<span class="pl-c1">0</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-abstract_context_manager-py-LC42" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">yield</span> <span class="pl-s1">file</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L43" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="43"></td>
          <td id="file-abstract_context_manager-py-LC43" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L44" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="44"></td>
          <td id="file-abstract_context_manager-py-LC44" class="blob-code blob-code-inner js-file-line">            <span class="pl-en">print</span>(<span class="pl-s">f"Failed to decrypt file: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L45" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="45"></td>
          <td id="file-abstract_context_manager-py-LC45" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">finally</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L46" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="46"></td>
          <td id="file-abstract_context_manager-py-LC46" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">if</span> <span class="pl-s1">file</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L47" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="47"></td>
          <td id="file-abstract_context_manager-py-LC47" class="blob-code blob-code-inner js-file-line">                <span class="pl-s1">file</span>.<span class="pl-en">close</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L48" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="48"></td>
          <td id="file-abstract_context_manager-py-LC48" class="blob-code blob-code-inner js-file-line">                <span class="pl-en">print</span>(<span class="pl-s">f"File decryption completed and file <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">path</span><span class="pl-kos">}</span></span> has been closed."</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L49" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="49"></td>
          <td id="file-abstract_context_manager-py-LC49" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L50" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="50"></td>
          <td id="file-abstract_context_manager-py-LC50" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Example usage</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L51" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="51"></td>
          <td id="file-abstract_context_manager-py-LC51" class="blob-code blob-code-inner js-file-line"><span class="pl-s1">key</span> <span class="pl-c1">=</span> <span class="pl-v">Fernet</span>.<span class="pl-en">generate_key</span>()  <span class="pl-c"># Normally you would store and retrieve this securely</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L52" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="52"></td>
          <td id="file-abstract_context_manager-py-LC52" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L53" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="53"></td>
          <td id="file-abstract_context_manager-py-LC53" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">encryptor</span> <span class="pl-c1">=</span> <span class="pl-v">FileEncryptor</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L54" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="54"></td>
          <td id="file-abstract_context_manager-py-LC54" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">decryptor</span> <span class="pl-c1">=</span> <span class="pl-v">FileDecryptor</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L55" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="55"></td>
          <td id="file-abstract_context_manager-py-LC55" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Encrypt data</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L56" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="56"></td>
          <td id="file-abstract_context_manager-py-LC56" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">with</span> <span class="pl-s1">encryptor</span>.<span class="pl-en">secure_file_handler</span>(<span class="pl-s">'testfile.txt'</span>, <span class="pl-s">'w+'</span>, <span class="pl-s1">key</span>) <span class="pl-k">as</span> <span class="pl-s1">file</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L57" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="57"></td>
          <td id="file-abstract_context_manager-py-LC57" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">file</span>.<span class="pl-en">write</span>(<span class="pl-s">"Sensitive data that needs encryption."</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L58" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="58"></td>
          <td id="file-abstract_context_manager-py-LC58" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"># Decrypt data</span></td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L59" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="59"></td>
          <td id="file-abstract_context_manager-py-LC59" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">with</span> <span class="pl-s1">decryptor</span>.<span class="pl-en">secure_file_handler</span>(<span class="pl-s">'testfile.txt'</span>, <span class="pl-s">'r+'</span>, <span class="pl-s1">key</span>) <span class="pl-k">as</span> <span class="pl-s1">file</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_context_manager-py-L60" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="60"></td>
          <td id="file-abstract_context_manager-py-LC60" class="blob-code blob-code-inner js-file-line">        <span class="pl-en">print</span>(<span class="pl-s">"Decrypted content:"</span>, <span class="pl-s1">file</span>.<span class="pl-en">read</span>())</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/a9ad9c3014703cf00579c0c5a71735a8/raw/8e90c98f7da33042fe84a4b0c7db9f4eb48848a8/abstract_context_manager.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/a9ad9c3014703cf00579c0c5a71735a8#file-abstract_context_manager-py" class="Link--inTextBlock">
          abstract_context_manager.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>the contextlib library also provides constructs for defining async context managers which are invaluable when working with async code. This is esspecially relevant when dealing with many types of connections such as database connections or API connections:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist129921473\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot; data-color-mode=\&quot;light\&quot; data-light-theme=\&quot;light\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container\&quot;>\n  <div id=\&quot;file-abstract_async_context_manager-py\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-python  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Python\&quot; data-tagsearch-path=\&quot;abstract_async_context_manager.py\&quot;>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>from</span> <span class=pl-s1>abc</span> <span class=pl-k>import</span> <span class=pl-v>ABC</span>, <span class=pl-s1>abstractmethod</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>asyncio</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>asyncpg</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>import</span> <span class=pl-s1>time</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>AsyncDatabaseManager</span>(<span class=pl-v>ABC</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-en>@<span class=pl-s1>abstractmethod</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>async</span> <span class=pl-k>def</span> <span class=pl-en>query</span>(<span class=pl-s1>self</span>, <span class=pl-s1>dsn</span>, <span class=pl-s1>sql</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;&amp;quot;&amp;quot;An asynchronous context manager for executing and timing database queries.&amp;quot;&amp;quot;&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>pass</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>class</span> <span class=pl-v>PostgreSQLQueryManager</span>(<span class=pl-v>AsyncDatabaseManager</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>async</span> <span class=pl-k>def</span> <span class=pl-en>query</span>(<span class=pl-s1>self</span>, <span class=pl-s1>dsn</span>, <span class=pl-s1>sql</span>):</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s1>conn</span> <span class=pl-c1>=</span> <span class=pl-c1>None</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>try</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>conn</span> <span class=pl-c1>=</span> <span class=pl-k>await</span> <span class=pl-s1>asyncpg</span>.<span class=pl-en>connect</span>(<span class=pl-s1>dsn</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>start_time</span> <span class=pl-c1>=</span> <span class=pl-s1>time</span>.<span class=pl-en>time</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-s1>result</span> <span class=pl-c1>=</span> <span class=pl-k>await</span> <span class=pl-s1>conn</span>.<span class=pl-en>fetch</span>(<span class=pl-s1>sql</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>yield</span> <span class=pl-s1>result</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>except</span> <span class=pl-s1>asyncpg</span>.<span class=pl-v>PostgresError</span> <span class=pl-k>as</span> <span class=pl-s1>e</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;Query failed: <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>e</span><span class=pl-kos>}</span></span>&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>finally</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-k>if</span> <span class=pl-s1>conn</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-k>await</span> <span class=pl-s1>conn</span>.<span class=pl-en>close</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>                <span class=pl-en>print</span>(<span class=pl-s>f&amp;quot;Query took <span class=pl-s1><span class=pl-kos>{</span><span class=pl-s1>time</span>.<span class=pl-en>time</span>() <span class=pl-c1>-</span> <span class=pl-s1>start_time</span>:.2f<span class=pl-kos>}</span></span> seconds to execute and connection has been closed.&amp;quot;</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-c># Usage example</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>async</span> <span class=pl-k>def</span> <span class=pl-en>main</span>():</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>dsn</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;postgresql://user:password@localhost:5432/mydatabase&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>sql</span> <span class=pl-c1>=</span> <span class=pl-s>&amp;quot;SELECT * FROM my_table&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>manager</span> <span class=pl-c1>=</span> <span class=pl-v>PostgreSQLQueryManager</span>()</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-k>async</span> <span class=pl-k>with</span> <span class=pl-s1>manager</span>.<span class=pl-en>query</span>(<span class=pl-s1>dsn</span>, <span class=pl-s1>sql</span>) <span class=pl-k>as</span> <span class=pl-s1>result</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-k>for</span> <span class=pl-s1>record</span> <span class=pl-c1>in</span> <span class=pl-s1>result</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>            <span class=pl-en>print</span>(<span class=pl-s1>record</span>)</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-k>if</span> <span class=pl-s1>__name__</span> <span class=pl-c1>==</span> <span class=pl-s>&amp;quot;__main__&amp;quot;</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-abstract_async_context_manager-py-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-abstract_async_context_manager-py-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s1>asyncio</span>.<span class=pl-en>run</span>(<span class=pl-en>main</span>())</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/67da6f6fc5ae83373c4a9c15a03b1fdf/raw/ef7624261e42c5793537e1fc66251c52811e3ba1/abstract_async_context_manager.py\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/67da6f6fc5ae83373c4a9c15a03b1fdf#file-abstract_async_context_manager-py\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          abstract_async_context_manager.py\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-1831e7b47678.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-1831e7b47678.css"><div id="gist129921473" class="gist">
    <div class="gist-file" data-color-mode="light" data-light-theme="light">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container">
  <div id="file-abstract_async_context_manager-py" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-python  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Python" data-tagsearch-path="abstract_async_context_manager.py">
        <tbody><tr>
          <td id="file-abstract_async_context_manager-py-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-abstract_async_context_manager-py-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">from</span> <span class="pl-s1">abc</span> <span class="pl-k">import</span> <span class="pl-v">ABC</span>, <span class="pl-s1">abstractmethod</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-abstract_async_context_manager-py-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">asyncio</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-abstract_async_context_manager-py-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">asyncpg</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-abstract_async_context_manager-py-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-k">import</span> <span class="pl-s1">time</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-abstract_async_context_manager-py-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-abstract_async_context_manager-py-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">AsyncDatabaseManager</span>(<span class="pl-v">ABC</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-abstract_async_context_manager-py-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">@<span class="pl-s1">abstractmethod</span></span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-abstract_async_context_manager-py-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">query</span>(<span class="pl-s1">self</span>, <span class="pl-s1">dsn</span>, <span class="pl-s1">sql</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-abstract_async_context_manager-py-LC9" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"""An asynchronous context manager for executing and timing database queries."""</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-abstract_async_context_manager-py-LC10" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">pass</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-abstract_async_context_manager-py-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-abstract_async_context_manager-py-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-k">class</span> <span class="pl-v">PostgreSQLQueryManager</span>(<span class="pl-v">AsyncDatabaseManager</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-abstract_async_context_manager-py-LC13" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">query</span>(<span class="pl-s1">self</span>, <span class="pl-s1">dsn</span>, <span class="pl-s1">sql</span>):</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-abstract_async_context_manager-py-LC14" class="blob-code blob-code-inner js-file-line">        <span class="pl-s1">conn</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-abstract_async_context_manager-py-LC15" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">try</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-abstract_async_context_manager-py-LC16" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">conn</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">asyncpg</span>.<span class="pl-en">connect</span>(<span class="pl-s1">dsn</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-abstract_async_context_manager-py-LC17" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">start_time</span> <span class="pl-c1">=</span> <span class="pl-s1">time</span>.<span class="pl-en">time</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-abstract_async_context_manager-py-LC18" class="blob-code blob-code-inner js-file-line">            <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">conn</span>.<span class="pl-en">fetch</span>(<span class="pl-s1">sql</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-abstract_async_context_manager-py-LC19" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">yield</span> <span class="pl-s1">result</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-abstract_async_context_manager-py-LC20" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">except</span> <span class="pl-s1">asyncpg</span>.<span class="pl-v">PostgresError</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-abstract_async_context_manager-py-LC21" class="blob-code blob-code-inner js-file-line">            <span class="pl-en">print</span>(<span class="pl-s">f"Query failed: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-abstract_async_context_manager-py-LC22" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">finally</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-abstract_async_context_manager-py-LC23" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">if</span> <span class="pl-s1">conn</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-abstract_async_context_manager-py-LC24" class="blob-code blob-code-inner js-file-line">                <span class="pl-k">await</span> <span class="pl-s1">conn</span>.<span class="pl-en">close</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-abstract_async_context_manager-py-LC25" class="blob-code blob-code-inner js-file-line">                <span class="pl-en">print</span>(<span class="pl-s">f"Query took <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">time</span>.<span class="pl-en">time</span>() <span class="pl-c1">-</span> <span class="pl-s1">start_time</span>:.2f<span class="pl-kos">}</span></span> seconds to execute and connection has been closed."</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-abstract_async_context_manager-py-LC26" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-abstract_async_context_manager-py-LC27" class="blob-code blob-code-inner js-file-line"><span class="pl-c"># Usage example</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-abstract_async_context_manager-py-LC28" class="blob-code blob-code-inner js-file-line"><span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">main</span>():</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-abstract_async_context_manager-py-LC29" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">dsn</span> <span class="pl-c1">=</span> <span class="pl-s">"postgresql://user:password@localhost:5432/mydatabase"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-abstract_async_context_manager-py-LC30" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">sql</span> <span class="pl-c1">=</span> <span class="pl-s">"SELECT * FROM my_table"</span></td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-abstract_async_context_manager-py-LC31" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">manager</span> <span class="pl-c1">=</span> <span class="pl-v">PostgreSQLQueryManager</span>()</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-abstract_async_context_manager-py-LC32" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">async</span> <span class="pl-k">with</span> <span class="pl-s1">manager</span>.<span class="pl-en">query</span>(<span class="pl-s1">dsn</span>, <span class="pl-s1">sql</span>) <span class="pl-k">as</span> <span class="pl-s1">result</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-abstract_async_context_manager-py-LC33" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">for</span> <span class="pl-s1">record</span> <span class="pl-c1">in</span> <span class="pl-s1">result</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-abstract_async_context_manager-py-LC34" class="blob-code blob-code-inner js-file-line">            <span class="pl-en">print</span>(<span class="pl-s1">record</span>)</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-abstract_async_context_manager-py-LC35" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-abstract_async_context_manager-py-LC36" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:</td>
        </tr>
        <tr>
          <td id="file-abstract_async_context_manager-py-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-abstract_async_context_manager-py-LC37" class="blob-code blob-code-inner js-file-line">    <span class="pl-s1">asyncio</span>.<span class="pl-en">run</span>(<span class="pl-en">main</span>())</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/67da6f6fc5ae83373c4a9c15a03b1fdf/raw/ef7624261e42c5793537e1fc66251c52811e3ba1/abstract_async_context_manager.py" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/67da6f6fc5ae83373c4a9c15a03b1fdf#file-abstract_async_context_manager-py" class="Link--inTextBlock">
          abstract_async_context_manager.py
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><h2>Abstract Collections</h2><p>The python standard library provides ABC class templates for specific types of classes in the <a href="https://docs.python.org/3/library/collections.abc.html">collections library</a>. These can be used as development guides when developing more complex code constructs such as iterators and asynchronous code. It is beyond the scope of this article to delve deeper into the implementation of these (potentially) performance enhancing implementations.</p><div><hr></div><h1>Concluding remarks</h1><p>That&#8217;s it for abstract base classes! Although simple, abstract base classes can be an invaluable component for generating inheritance based object-oriented data models for your python code bases. However, abstract base classes are still not the complete picture.</p><p>Although we can define what our classes should implement, we are still in the dark when it comes to types. Also, what if we want to define more stringent implementation control without creating strong object dependencies? Expanding into typing will help us address some of these issues.</p><p>If you have found this helpful or if you want to stay up to date on follow up articles on the data code model or related topic, do not hesitate to subscribe below or share the post.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/p/data-code-modelling-abstract-base?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thank you for reading Tony&#8217;s Substack. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/p/data-code-modelling-abstract-base?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/p/data-code-modelling-abstract-base?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h1>Resources</h1><ul><li><p>Abstract Base Class Documentation <a href="https://docs.python.org/3/library/abc.html">https://docs.python.org/3/library/abc.html</a></p></li><li><p>Abstract Base Class Implementation <a href="https://github.com/python/cpython/blob/3.12/Lib/abc.py">https://github.com/python/cpython/blob/3.12/Lib/abc.py</a></p></li><li><p>Difference between class method, static method and regular method <a href="https://realpython.com/courses/python-method-types/#:~:text=Regular">https://realpython.com/courses/python-method-types/#:~:text=Regular</a></p></li><li><p><a href="https://github.com/lord63/awesome-python-decorator">https://github.com/lord63/awesome-python-decorator</a> has a good collection on python decorator resources</p></li><li><p><a href="https://www.integralist.co.uk/posts/python-generators/">https://www.integralist.co.uk/posts/python-generators/</a> &#8658; has a good collection on iterators, generators and coroutines.</p></li><li><p><a href="https://docs.python.org/3.7/library/collections.abc.html#collections.abc.Iterator">https://docs.python.org/3.7/library/collections.abc.html#collections.abc.Iterator</a> &#8658; provides a list of built in abstract base classes</p></li><li><p>abc collections source code &#8658; <a href="https://github.com/python/cpython/blob/3.12/Lib/_collections_abc.py">https://github.com/python/cpython/blob/3.12/Lib/_collections_abc.py</a></p></li><li><p>contextlib &#8658; <a href="https://docs.python.org/3/library/contextlib.html#module-contextlib">https://docs.python.org/3/library/contextlib.html#module-contextlib</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Finding Stakeholder-Data Fit]]></title><description><![CDATA[The ever lasting quest]]></description><link>https://www.blog.zelytics.tech/p/finding-stakeholder-data-fit</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/finding-stakeholder-data-fit</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Sat, 24 Feb 2024 16:56:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe06bfb94-797e-445f-ba0b-8117553a9aa7_800x800.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the hardest things in data is proving value.</p><p>What?</p><p>It helps to view any data initiative, small or large, as a small startup. In the startup world, one of the most important things to do is finding product-market fit.</p><p>This is all about understanding your customer and what they <em><strong>REALLY</strong></em> want.</p><p>In data, we can look at this in a similar way: How do we find out what efforts we should prioritize for our stakeholders?</p><p>In that spirit, here is a list of 30 questions to ask your stakeholders or yourself to figure out if the current efforts make sense:</p><ol><li><p>What are your top objectives for this week, month, quarter, and year?</p></li><li><p>What is a typical task you perform often and would like to see more automated?</p></li><li><p>What are the top objectives of your stakeholders?</p></li><li><p>How do you measure success?</p></li><li><p>What data sources are you already using?</p></li><li><p>What data sources would you like to use more of?</p></li><li><p>How long would it take our team to build this?</p></li><li><p>What is the estimated lifetime value of this work?</p></li><li><p>Is there a depreciated return on value over time?</p></li><li><p>How many engineering hours will it take to maintain?</p></li><li><p>Can the responsibility easily be transferred, or is this dependent on 1-2 people?</p></li><li><p>What is the opportunity cost of doing this? Put differently, what other pursuits would need to get sacrificed?</p></li><li><p>Does it make more sense to buy a solution or build something in-house?</p></li><li><p>How will our team measure engagement of our new solutions with stakeholders?</p></li><li><p>In dollar terms, how much labor cost is this solution saving over time?</p></li><li><p>Does this solution drive more revenue? How do we prove this?</p></li><li><p>Is this solution reducing company liability? If so, how and how much?</p></li><li><p>Has this been done before? If so, how much time did it take them? If not, is there a good way to estimate how much time this would take to do?</p></li><li><p>How is this data going to be acted upon? If a stakeholder requests real-time but the actions are manual, consider what real-time really means here.</p></li><li><p>Apply Occam's razor to your solution: How can we achieve the results with the least amount of necessary permutations in our existing infrastructure.</p></li><li><p>Would this solution be very visible to the organization? If not, it may be harder to defend the value of this effort.</p></li><li><p>Is anyone else in the organization currently tackling this problem? Are we duplicating efforts? This requires talking to more people than just your direct stakeholders.</p></li><li><p>Has there been any effort in the past to address this issue? If so, get all the possible learnings you can get.</p></li><li><p>Are we considering this because it&#8217;s popular knowledge or a new shiny state-of-the-art tool, or is it truly relevant for our business?</p></li><li><p>How bad would it be if this effort fails?</p></li><li><p>What would be the repercussions of not doing this? How fast will the business feel the impact? How large would this impact be? Be concrete.</p></li><li><p>Can we deploy a quick minimum viable product to get buy-in earlier?</p></li><li><p>How confident am I we can deliver on our promises within a reasonable amount of time?</p></li><li><p>How many dependencies does this project have? Is this something we can run mostly internally, or does it need coordination with a lot of other teams?</p></li><li><p>Does this solution keep pace with the growth in scale of the business? How long will it take before this becomes obsolete?</p></li></ol><p>What are some questions you like to ask stakeholders?</p><p>Like content like this? Support the newsletter with a subscribe!<br></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Setting up a dbt development environment with VScode Devcontainers]]></title><description><![CDATA[Using open source tooling.]]></description><link>https://www.blog.zelytics.tech/p/setting-up-a-dbt-development-environment</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/setting-up-a-dbt-development-environment</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Sat, 24 Feb 2024 15:55:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jvYS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p><h2>It all starts with local development environments</h2><p>There&#8217;s several ways to drive impact in a tech driven organisation.</p><p>One of the ways to drive significant impact is improving the development workflow of other developers.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>It&#8217;s a simple calculus: let&#8217;s say we save 5 hours of development time for a typical analytics engineer. If we have 10 AE&#8217;s, that amounts to 50 hours a week. Translated to salaries, this can amount to several thousands of dollars in generated value each week. The payout in productivity is exponential over time.</p><p>If VScode is the default code editor of most of your team, VScode devcontainers are a great way to go about this.</p><h2>What is a VScode devcontainer?</h2><p><a href="https://code.visualstudio.com/docs/devcontainers/containers">A Visual Studio Code (VSCode) Development Container</a>, or devcontainer, is a feature provided by VSCode that allows developers to create and configure a consistent, containerized development environment.</p><p>This feature utilizes Docker containers to encapsulate the development environment, ensuring that it includes all the necessary dependencies, tools, and settings required for a project.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jvYS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jvYS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 424w, https://substackcdn.com/image/fetch/$s_!jvYS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 848w, https://substackcdn.com/image/fetch/$s_!jvYS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 1272w, https://substackcdn.com/image/fetch/$s_!jvYS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jvYS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png" width="1456" height="605" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:605,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:324163,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jvYS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 424w, https://substackcdn.com/image/fetch/$s_!jvYS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 848w, https://substackcdn.com/image/fetch/$s_!jvYS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 1272w, https://substackcdn.com/image/fetch/$s_!jvYS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8b708f8-4df6-4c7f-a30a-e5647c7f8db4_2000x831.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Fig 1.</strong> VScode devcontainers overview</figcaption></figure></div><p>Before we dive into create a local environment, let&#8217;s first consider some of the key concepts for configuration.</p><h2>Settings.json</h2><p>For any VScode environment, it is possible to configure the settings of the environment in <code>settings.json</code> . <a href="https://code.visualstudio.com/docs/getstarted/settings#_settingsjson">This json file</a> can be used to set configurations of your VScode environment as well as all of the currently installed extensions. Try this for example:</p><blockquote><p>(Mac) <code>CMD+SHIFT+P</code> <code>&gt; Preferences: Open User Settings (JSON)</code></p><p>(Windows) <code>CTRL+SHIFT+P</code> <code>&gt; Preferences: Open User Settings (JSON)</code></p></blockquote><p>This will open the <code>settings.json</code> file for your user. Now try add the following to the json</p><pre><code><code>"workbench.colorCustomizations": {
    "activityBar.background": "#ff00d4",
}</code></code></pre><p>You should see your activity bar turn pink now. That&#8217;s sweet but we want to do more than that ofcourse.</p><h2>Dockerfile and Docker compose</h2><p>VScode devcontainers can be built with regular Dockerfiles. My suggestions would be to use any official base image on Dockerhub. As we will be setting up dbt, my suggestion would be to use a <a href="https://hub.docker.com/_/python">official python image</a>. Make sure to consider the following things:</p><ul><li><p><strong>Docker image size:</strong> The larger the docker image, the longer it will take to do the initial download and build for your environment. Python dockerhub has images tagged with <code>slim</code> which are generally 3X smaller. These are based on Debian.</p></li><li><p><strong>DBT python version compatibility:</strong> At the date of this article, this can be found in the dbt docs at <a href="https://docs.getdbt.com/faqs/Core/install-python-compatibility">https://docs.getdbt.com/faqs/Core/install-python-compatibility</a></p></li><li><p><strong>Opt for docker compose over running only dockerfile.</strong> Using docker compose allows us a greater deal of flexibility when it comes to setting up the docker environment around the dev container (i.e any custom co-containers, networks, etc..).</p></li></ul><h2>Devcontainer.json</h2><p>The devcontainer.json is the main configuration file for the devcontainer. It can be viewed as a combination of docker orchestration commands and the <code>settings.json</code> file. You can view the documentation on this file <a href="https://containers.dev/implementors/json_reference/">here</a>. To view the full json schema spec, check the <a href="https://github.com/devcontainers/spec/blob/main/schemas/devContainer.base.schema.json">devcontainers specification</a>.</p><blockquote><p><strong>&#128161; Tip:</strong> As raw json schemas tend to be a bit difficult to read, try using <a href="https://github.com/coveooss/json-schema-for-humans">https://github.com/coveooss/json-schema-for-humans</a> to create a nicer representation for easy viewing.</p></blockquote><p>I&#8217;ve published a more readable HTML document for the schema generated with json-schema-for-humans <a href="https://github.com/2tony2/dbt-devcontainer-demo/tree/main/attributes">here</a>. Feel free to clone the repo and open the HTML file on your local machine.</p><p>The specification are quite extensive, but it helps to think of the settings in a couple of broad categories:</p><ul><li><p><strong>Devcontainer metadata</strong> &#8658; project name, where to find files, etc&#8230;</p></li><li><p><strong>Container specifications</strong> &#8658; Configuration for docker, docker compose, etc&#8230;</p></li><li><p><strong>Customizations</strong> &#8658; Any settings you want to pass on to the <code>settings.json</code> in the devcontainer.</p></li><li><p><strong>Features</strong> &#8658; Configure what functionality can be included within the dev container to be used.</p></li></ul><h2>What is VScode devcontainers doing in the background</h2><p>The following general steps occur:</p><ul><li><p>First the container is built.</p></li><li><p>Then a VScode server instance is inititated within the devcontainer. Thus, the implementation is akin to running VScode server on a remote machine.</p></li><li><p>VScode server will install all extensions and configure any settings as provided in the configuration for the devcontainer.</p></li><li><p>There&#8217;s some quality of life improvements. For example, whenever a browser is invoked to open on a remote without a desktop, usually this fails without any additional configuration. VScode however uses a custom configuration to actually open the browser on your host machine!</p><ul><li><p>Keep in mind with this however, this can lead to unexpected behavior at first when working with things like browser based SSO. These applications will typically need additional configuration to work.</p></li></ul></li></ul><h1>Creating the setup!</h1><p>Now that we have covered the main concepts, let&#8217;s start applying them by creating a local dev environment with dbt.</p><h2>Jaffle shop</h2><p>For demo purposes, I will use the official dbt example project <a href="https://github.com/dbt-labs/jaffle_shop.git">jaffle shop</a> as a base project to showcase the devcontainer setup. You can check the jaffle shop demo together with the dbt devcontainer configuration in this public repo <a href="https://github.com/2tony2/dbt-devcontainer-demo/tree/main">https://github.com/2tony2/dbt-devcontainer-demo/tree/main</a>. Feel free to clone, fork and play around with it.</p><h2>Installation requirements on your local machine</h2><p>To make sure you&#8217;re running an as stable as possible deployment, ensure you have the following things installed / up to date:</p><ul><li><p>The Operating System of your machine</p></li><li><p><a href="https://www.docker.com/products/docker-desktop/">Docker desktop</a></p></li><li><p>The latest version of VScode</p></li><li><p>Have at least the following VScode extensions installed:</p><ul><li><p><code>ms-vscode-remote.remote-containers</code></p></li><li><p><code>ms-azuretools.vscode-docker</code></p></li><li><p><code>ms-vscode.remote-explorer</code></p></li></ul></li></ul><h2>File setup</h2><p>To create a devcontainer environment, make sure to clone a repo containing your dbt project (or the <a href="https://github.com/2tony2/dbt-devcontainer-demo/tree/main">example project here</a> if you&#8217;re following along).</p><p>Next, create a folder called <code>.devcontainer</code> at the root of your github repo. VScode will automatically pick up any devcontainer configurations from this folder.</p><p>Create the following empty files within the .devcontainer:</p><ul><li><p>Dockerfile</p></li><li><p>docker-compose.yaml</p></li><li><p>devcontainer.json</p></li><li><p>devcontainer.env</p></li><li><p>requirements.txt</p></li><li><p>init (subfolder)</p></li></ul><p>We will now go over the configuration for each individual file</p><h2>Dockerfile</h2><p>For the Dockerfile we have the following configuration</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist128609598\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container file-box\&quot;>\n  <div id=\&quot;file-dockerfile\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-dockerfile  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Dockerfile\&quot; data-tagsearch-path=\&quot;Dockerfile\&quot;>\n        <tr>\n          <td id=\&quot;file-dockerfile-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span>##################################################</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span>#### SETTING OPERATING SYSTEM #####</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span>##################################################</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> This is an official python image.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>FROM</span> python:3.11.6-bookworm</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Set the user to root.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>USER</span> root</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Prevent interactive popups when initializing debian.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>ENV</span> DEBIAN_FRONTEND=noninteractive</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Set up a dir for our stuff</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> mkdir -p /devcontainer</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> chmod -R 777 /devcontainer</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Install OS packages</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> apt-get update &amp;amp;&amp;amp; apt-get install -y \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    build-essential \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    curl \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    git \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    cmake \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    wget \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    zsh</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span>##################################################</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span>#### CONFIGURING PYTHON AND INIT SCRIPTS #####</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span>##################################################</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Set up an installation env</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>COPY</span> ./scripts /devcontainer/init</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>COPY</span> ./requirements.txt /devcontainer/requirements.txt</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Install python packages</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> pip install --upgrade pip --disable-pip-version-check</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> pip install -r /init/requirements.txt --disable-pip-version-check</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> The following will persist shell history between sessions</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> SNIPPET=<span class=\&quot;pl-s\&quot;>&amp;quot;export PROMPT_COMMAND=&amp;#39;history -a&amp;#39; &amp;amp;&amp;amp; export HISTFILE=/commandhistory/.bash_history&amp;quot;</span> \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    &amp;amp;&amp;amp; echo <span class=\&quot;pl-s\&quot;>&amp;quot;$SNIPPET&amp;quot;</span> &amp;gt;&amp;gt; <span class=\&quot;pl-s\&quot;>&amp;quot;/root/.bashrc&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L43\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;43\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC43\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> This works for other shells too, the following works for ZSH.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L44\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;44\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC44\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-k\&quot;>RUN</span> SNIPPET=<span class=\&quot;pl-s\&quot;>&amp;quot;export HISTFILE=/commandhistory/.zsh_history; setopt INC_APPEND_HISTORY&amp;quot;</span> \\</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-dockerfile-L45\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;45\&quot;></td>\n          <td id=\&quot;file-dockerfile-LC45\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    &amp;amp;&amp;amp; echo <span class=\&quot;pl-s\&quot;>&amp;quot;$SNIPPET&amp;quot;</span> &amp;gt;&amp;gt; <span class=\&quot;pl-s\&quot;>&amp;quot;/root/.zshrc&amp;quot;</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/b29e172332c2765fe560e9be01b1227c/raw/805af3d0bfbd35a2cc27c40286bd4c9c6f222e05/Dockerfile\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/b29e172332c2765fe560e9be01b1227c#file-dockerfile\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          Dockerfile\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css"><div id="gist128609598" class="gist">
    <div class="gist-file">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-dockerfile" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-dockerfile  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Dockerfile" data-tagsearch-path="Dockerfile">
        <tbody><tr>
          <td id="file-dockerfile-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-dockerfile-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span>##################################################</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-dockerfile-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span>#### SETTING OPERATING SYSTEM #####</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-dockerfile-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span>##################################################</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-dockerfile-LC4" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-dockerfile-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> This is an official python image.</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-dockerfile-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-k">FROM</span> python:3.11.6-bookworm</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-dockerfile-LC7" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-dockerfile-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> Set the user to root.</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-dockerfile-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-k">USER</span> root</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-dockerfile-LC10" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-dockerfile-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> Prevent interactive popups when initializing debian.</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-dockerfile-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-k">ENV</span> DEBIAN_FRONTEND=noninteractive</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-dockerfile-LC13" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-dockerfile-LC14" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> Set up a dir for our stuff</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-dockerfile-LC15" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> mkdir -p /devcontainer</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-dockerfile-LC16" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> chmod -R 777 /devcontainer</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-dockerfile-LC17" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-dockerfile-LC18" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> Install OS packages</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-dockerfile-LC19" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> apt-get update &amp;&amp; apt-get install -y \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-dockerfile-LC20" class="blob-code blob-code-inner js-file-line">    build-essential \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-dockerfile-LC21" class="blob-code blob-code-inner js-file-line">    curl \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-dockerfile-LC22" class="blob-code blob-code-inner js-file-line">    git \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-dockerfile-LC23" class="blob-code blob-code-inner js-file-line">    cmake \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-dockerfile-LC24" class="blob-code blob-code-inner js-file-line">    wget \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-dockerfile-LC25" class="blob-code blob-code-inner js-file-line">    zsh</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-dockerfile-LC26" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-dockerfile-LC27" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span>##################################################</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-dockerfile-LC28" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span>#### CONFIGURING PYTHON AND INIT SCRIPTS #####</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-dockerfile-LC29" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span>##################################################</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-dockerfile-LC30" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-dockerfile-LC31" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> Set up an installation env</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-dockerfile-LC32" class="blob-code blob-code-inner js-file-line"><span class="pl-k">COPY</span> ./scripts /devcontainer/init</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-dockerfile-LC33" class="blob-code blob-code-inner js-file-line"><span class="pl-k">COPY</span> ./requirements.txt /devcontainer/requirements.txt</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-dockerfile-LC34" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-dockerfile-LC35" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> Install python packages</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-dockerfile-LC36" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> pip install --upgrade pip --disable-pip-version-check</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-dockerfile-LC37" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> pip install -r /init/requirements.txt --disable-pip-version-check</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-dockerfile-LC38" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-dockerfile-LC39" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> The following will persist shell history between sessions</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-dockerfile-LC40" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> SNIPPET=<span class="pl-s">"export PROMPT_COMMAND='history -a' &amp;&amp; export HISTFILE=/commandhistory/.bash_history"</span> \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-dockerfile-LC41" class="blob-code blob-code-inner js-file-line">    &amp;&amp; echo <span class="pl-s">"$SNIPPET"</span> &gt;&gt; <span class="pl-s">"/root/.bashrc"</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-dockerfile-LC42" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L43" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="43"></td>
          <td id="file-dockerfile-LC43" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#</span> This works for other shells too, the following works for ZSH.</span></td>
        </tr>
        <tr>
          <td id="file-dockerfile-L44" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="44"></td>
          <td id="file-dockerfile-LC44" class="blob-code blob-code-inner js-file-line"><span class="pl-k">RUN</span> SNIPPET=<span class="pl-s">"export HISTFILE=/commandhistory/.zsh_history; setopt INC_APPEND_HISTORY"</span> \</td>
        </tr>
        <tr>
          <td id="file-dockerfile-L45" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="45"></td>
          <td id="file-dockerfile-LC45" class="blob-code blob-code-inner js-file-line">    &amp;&amp; echo <span class="pl-s">"$SNIPPET"</span> &gt;&gt; <span class="pl-s">"/root/.zshrc"</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/b29e172332c2765fe560e9be01b1227c/raw/805af3d0bfbd35a2cc27c40286bd4c9c6f222e05/Dockerfile" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/b29e172332c2765fe560e9be01b1227c#file-dockerfile" class="Link--inTextBlock">
          Dockerfile
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>What this docker file do in general is install python, intall some OS dependencies, install python dependencies as defined in requirements.txt and store shell history so it can be passed from devcontainer to devcontainer.</p><p>Next, we set up the docker compose.</p><h2>Docker compose yaml</h2><p>A super simple docker compose file may look something like this:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist128609616\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container file-box\&quot;>\n  <div id=\&quot;file-docker-compose-yml\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-yaml  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;YAML\&quot; data-tagsearch-path=\&quot;Docker-compose.yml\&quot;>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>version</span>: <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;#39;</span>3<span class=\&quot;pl-pds\&quot;>&amp;#39;</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>volumes</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=\&quot;pl-ent\&quot;>local-dbt-env-shell-history</span>: <span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> This basically let&amp;#39;s docker auto-manage this volume.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>services</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=\&quot;pl-ent\&quot;>local-dbt-env</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>profiles</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>development</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>platform</span>: <span class=\&quot;pl-s\&quot;>linux/amd64 </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> We force the platform for consistency.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>build</span>: </td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>context</span>: <span class=\&quot;pl-s\&quot;>.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>dockerfile</span>: <span class=\&quot;pl-s\&quot;>Dockerfile</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>volumes</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>/var/run/docker.sock:/var/run/docker-host.sock </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Forwards the local Docker socket to the container.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>local-dbt-env-shell-history:/commandhistory </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Volume that stores shell history between sessions</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Overrides default command so things don&amp;#39;t shut down after the process ends.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>command</span>: <span class=\&quot;pl-s\&quot;>/bin/zsh -c &amp;quot;while sleep 1000; do :; done&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-yml-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-docker-compose-yml-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>env_file</span>: <span class=\&quot;pl-s\&quot;>devcontainer.env</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/782bb3b8a3da39925f32c2c0aa7cf004/raw/ffb7f6e020e6e1f4246c207039d22ab276dc83e7/Docker-compose.yml\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/782bb3b8a3da39925f32c2c0aa7cf004#file-docker-compose-yml\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          Docker-compose.yml\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css"><div id="gist128609616" class="gist">
    <div class="gist-file">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-docker-compose-yml" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-yaml  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="YAML" data-tagsearch-path="Docker-compose.yml">
        <tbody><tr>
          <td id="file-docker-compose-yml-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-docker-compose-yml-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">version</span>: <span class="pl-s"><span class="pl-pds">'</span>3<span class="pl-pds">'</span></span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-docker-compose-yml-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-docker-compose-yml-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">volumes</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-docker-compose-yml-LC4" class="blob-code blob-code-inner js-file-line">  <span class="pl-ent">local-dbt-env-shell-history</span>: <span class="pl-c"><span class="pl-c">#</span> This basically let's docker auto-manage this volume.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-docker-compose-yml-LC5" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-docker-compose-yml-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">services</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-docker-compose-yml-LC7" class="blob-code blob-code-inner js-file-line">  <span class="pl-ent">local-dbt-env</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-docker-compose-yml-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">profiles</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-docker-compose-yml-LC9" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">development</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-docker-compose-yml-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">platform</span>: <span class="pl-s">linux/amd64 </span><span class="pl-c"><span class="pl-c">#</span> We force the platform for consistency.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-docker-compose-yml-LC11" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">build</span>: </td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-docker-compose-yml-LC12" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">context</span>: <span class="pl-s">.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-docker-compose-yml-LC13" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">dockerfile</span>: <span class="pl-s">Dockerfile</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-docker-compose-yml-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">volumes</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-docker-compose-yml-LC15" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">/var/run/docker.sock:/var/run/docker-host.sock </span><span class="pl-c"><span class="pl-c">#</span> Forwards the local Docker socket to the container.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-docker-compose-yml-LC16" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">local-dbt-env-shell-history:/commandhistory </span><span class="pl-c"><span class="pl-c">#</span> Volume that stores shell history between sessions</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-docker-compose-yml-LC17" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-docker-compose-yml-LC18" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"><span class="pl-c">#</span> Overrides default command so things don't shut down after the process ends.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-docker-compose-yml-LC19" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">command</span>: <span class="pl-s">/bin/zsh -c "while sleep 1000; do :; done"</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-yml-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-docker-compose-yml-LC20" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">env_file</span>: <span class="pl-s">devcontainer.env</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/782bb3b8a3da39925f32c2c0aa7cf004/raw/ffb7f6e020e6e1f4246c207039d22ab276dc83e7/Docker-compose.yml" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/782bb3b8a3da39925f32c2c0aa7cf004#file-docker-compose-yml" class="Link--inTextBlock">
          Docker-compose.yml
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>This is a simple setup that will create a <code>local-dbt-env</code> service and configure it to run the linux/amd64 version of the base image by default. The other configurations ensure command history is retained between sessions and the command will ensure the container keeps running after being created by introducing an infinite loop. We can pass on any environmental variables through the env_file.</p><p>An example of a more advanced setup which uses SSO to connect to snowflake would be the following:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist128609662\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container file-box\&quot;>\n  <div id=\&quot;file-docker-compose-sso-yml\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-yaml  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;YAML\&quot; data-tagsearch-path=\&quot;docker-compose-sso.yml\&quot;>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>version</span>: <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;#39;</span>3<span class=\&quot;pl-pds\&quot;>&amp;#39;</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>networks</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=\&quot;pl-ent\&quot;>local_dev_network</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>driver</span>: <span class=\&quot;pl-s\&quot;>bridge</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>ipam</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>driver</span>: <span class=\&quot;pl-s\&quot;>default</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>config</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        - <span class=\&quot;pl-ent\&quot;>subnet</span>: <span class=\&quot;pl-s\&quot;>172.23.0.0/16</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=\&quot;pl-ent\&quot;>gateway</span>: <span class=\&quot;pl-s\&quot;>172.23.0.1</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>volumes</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=\&quot;pl-ent\&quot;>local-dbt-env-shell-history</span>: <span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> This basically let&amp;#39;s docker auto-manage this volume.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-ent\&quot;>services</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=\&quot;pl-ent\&quot;>local-dbt-env</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>profiles</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>development</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>platform</span>: <span class=\&quot;pl-s\&quot;>linux/amd64 </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> We force the platform for consistency.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>build</span>: </td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>context</span>: <span class=\&quot;pl-s\&quot;>.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>dockerfile</span>: <span class=\&quot;pl-s\&quot;>Dockerfile</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>volumes</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>/var/run/docker.sock:/var/run/docker-host.sock </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Forwards the local Docker socket to the container.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>local-dbt-env-shell-history:/commandhistory </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Volume that stores shell history between sessions</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>\n</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> Overrides default command so things don&amp;#39;t shut down after the process ends.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>command</span>: <span class=\&quot;pl-s\&quot;>/bin/zsh -c &amp;quot;while sleep 1000; do :; done&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>env_file</span>: <span class=\&quot;pl-s\&quot;>devcontainer.env</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>ports</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>60000-60010:60000-60010<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span> <span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> port forward the port range reserved for dynamic port use.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>networks</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=\&quot;pl-ent\&quot;>local_dev_network</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=\&quot;pl-ent\&quot;>ipv4_address</span>: <span class=\&quot;pl-s\&quot;>172.23.0.2  </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> We assign a static ip for more stable functionality of the python snowflake connector authentication.</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=\&quot;pl-ent\&quot;>environment</span>:</td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-docker-compose-sso-yml-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-docker-compose-sso-yml-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      - <span class=\&quot;pl-s\&quot;>SF_AUTH_SOCKET_ADDR=172.23.0.2 </span><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#</span> this forces the snowflake connector to use the static ip we assigned to the container as the recipient of the SSO token.</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/80e2dc1196d36ce0d367a29b6e5ede15/raw/079ef61f913e469deea13799421e0a285952d79d/docker-compose-sso.yml\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/80e2dc1196d36ce0d367a29b6e5ede15#file-docker-compose-sso-yml\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          docker-compose-sso.yml\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css"><div id="gist128609662" class="gist">
    <div class="gist-file">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-docker-compose-sso-yml" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-yaml  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="YAML" data-tagsearch-path="docker-compose-sso.yml">
        <tbody><tr>
          <td id="file-docker-compose-sso-yml-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-docker-compose-sso-yml-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">version</span>: <span class="pl-s"><span class="pl-pds">'</span>3<span class="pl-pds">'</span></span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-docker-compose-sso-yml-LC2" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-docker-compose-sso-yml-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">networks</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-docker-compose-sso-yml-LC4" class="blob-code blob-code-inner js-file-line">  <span class="pl-ent">local_dev_network</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-docker-compose-sso-yml-LC5" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">driver</span>: <span class="pl-s">bridge</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-docker-compose-sso-yml-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">ipam</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-docker-compose-sso-yml-LC7" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">driver</span>: <span class="pl-s">default</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-docker-compose-sso-yml-LC8" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">config</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-docker-compose-sso-yml-LC9" class="blob-code blob-code-inner js-file-line">        - <span class="pl-ent">subnet</span>: <span class="pl-s">172.23.0.0/16</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-docker-compose-sso-yml-LC10" class="blob-code blob-code-inner js-file-line">          <span class="pl-ent">gateway</span>: <span class="pl-s">172.23.0.1</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-docker-compose-sso-yml-LC11" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-docker-compose-sso-yml-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">volumes</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-docker-compose-sso-yml-LC13" class="blob-code blob-code-inner js-file-line">  <span class="pl-ent">local-dbt-env-shell-history</span>: <span class="pl-c"><span class="pl-c">#</span> This basically let's docker auto-manage this volume.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-docker-compose-sso-yml-LC14" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-docker-compose-sso-yml-LC15" class="blob-code blob-code-inner js-file-line"><span class="pl-ent">services</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-docker-compose-sso-yml-LC16" class="blob-code blob-code-inner js-file-line">  <span class="pl-ent">local-dbt-env</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-docker-compose-sso-yml-LC17" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">profiles</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-docker-compose-sso-yml-LC18" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">development</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-docker-compose-sso-yml-LC19" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">platform</span>: <span class="pl-s">linux/amd64 </span><span class="pl-c"><span class="pl-c">#</span> We force the platform for consistency.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-docker-compose-sso-yml-LC20" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">build</span>: </td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-docker-compose-sso-yml-LC21" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">context</span>: <span class="pl-s">.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-docker-compose-sso-yml-LC22" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">dockerfile</span>: <span class="pl-s">Dockerfile</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-docker-compose-sso-yml-LC23" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">volumes</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-docker-compose-sso-yml-LC24" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">/var/run/docker.sock:/var/run/docker-host.sock </span><span class="pl-c"><span class="pl-c">#</span> Forwards the local Docker socket to the container.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-docker-compose-sso-yml-LC25" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">local-dbt-env-shell-history:/commandhistory </span><span class="pl-c"><span class="pl-c">#</span> Volume that stores shell history between sessions</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-docker-compose-sso-yml-LC26" class="blob-code blob-code-inner js-file-line">
</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-docker-compose-sso-yml-LC27" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"><span class="pl-c">#</span> Overrides default command so things don't shut down after the process ends.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-docker-compose-sso-yml-LC28" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">command</span>: <span class="pl-s">/bin/zsh -c "while sleep 1000; do :; done"</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-docker-compose-sso-yml-LC29" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">env_file</span>: <span class="pl-s">devcontainer.env</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-docker-compose-sso-yml-LC30" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">ports</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-docker-compose-sso-yml-LC31" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s"><span class="pl-pds">"</span>60000-60010:60000-60010<span class="pl-pds">"</span></span> <span class="pl-c"><span class="pl-c">#</span> port forward the port range reserved for dynamic port use.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-docker-compose-sso-yml-LC32" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">networks</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-docker-compose-sso-yml-LC33" class="blob-code blob-code-inner js-file-line">      <span class="pl-ent">local_dev_network</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-docker-compose-sso-yml-LC34" class="blob-code blob-code-inner js-file-line">        <span class="pl-ent">ipv4_address</span>: <span class="pl-s">172.23.0.2  </span><span class="pl-c"><span class="pl-c">#</span> We assign a static ip for more stable functionality of the python snowflake connector authentication.</span></td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-docker-compose-sso-yml-LC35" class="blob-code blob-code-inner js-file-line">    <span class="pl-ent">environment</span>:</td>
        </tr>
        <tr>
          <td id="file-docker-compose-sso-yml-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-docker-compose-sso-yml-LC36" class="blob-code blob-code-inner js-file-line">      - <span class="pl-s">SF_AUTH_SOCKET_ADDR=172.23.0.2 </span><span class="pl-c"><span class="pl-c">#</span> this forces the snowflake connector to use the static ip we assigned to the container as the recipient of the SSO token.</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/80e2dc1196d36ce0d367a29b6e5ede15/raw/079ef61f913e469deea13799421e0a285952d79d/docker-compose-sso.yml" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/80e2dc1196d36ce0d367a29b6e5ede15#file-docker-compose-sso-yml" class="Link--inTextBlock">
          docker-compose-sso.yml
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>I will expand on setting up more advanced docker networking configurations in another future article.</p><p>After we have our simple docker environment, let&#8217;s set up the main configuration for the VScode devcontainer.</p><h2>Devcontainer json</h2><p>This is going to be the main setup for the dev container:</p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist128609690\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container file-box\&quot;>\n  <div id=\&quot;file-devcontainer-json\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-json-with-comments  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path d=\&quot;M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;JSON with Comments\&quot; data-tagsearch-path=\&quot;devcontainer.json\&quot;>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;name&amp;quot;</span>: <span class=pl-s>&amp;quot;dbt dev env&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;dockerComposeFile&amp;quot;</span>: <span class=pl-s>&amp;quot;./docker-compose.yml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;service&amp;quot;</span>: <span class=pl-s>&amp;quot;local-dbt-env&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;runServices&amp;quot;</span>: <span class=pl-kos>[</span><span class=pl-s>&amp;quot;local-dbt-env&amp;quot;</span><span class=pl-kos>]</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L6\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;6\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC6\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;hostRequirements&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L7\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;7\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC7\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;cpus&amp;quot;</span>: <span class=pl-c1>4</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L8\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;8\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC8\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;memory&amp;quot;</span>: <span class=pl-s>&amp;quot;8gb&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L9\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;9\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC9\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;storage&amp;quot;</span>: <span class=pl-s>&amp;quot;30gb&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L10\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;10\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC10\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-kos>}</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L11\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;11\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC11\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;workspaceFolder&amp;quot;</span>: <span class=pl-s>&amp;quot;/devcontainer&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L12\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;12\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC12\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;shutdownAction&amp;quot;</span>: <span class=pl-s>&amp;quot;none&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L13\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;13\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC13\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;customizations&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L14\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;14\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC14\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;vscode&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L15\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;15\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC15\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-s>&amp;quot;settings&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L16\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;16\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC16\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;extensions.verifySignature&amp;quot;</span>: <span class=pl-c1>false</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L17\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;17\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC17\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;python.interpreter.infoVisibility&amp;quot;</span>: <span class=pl-s>&amp;quot;always&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L18\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;18\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC18\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;python.defaultInterpreterPath&amp;quot;</span>: <span class=pl-s>&amp;quot;/usr/local/bin/python&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L19\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;19\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC19\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;dbt.dbtPythonPathOverride&amp;quot;</span>: <span class=pl-s>&amp;quot;/usr/local/bin/python&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L20\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;20\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC20\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;files.associations&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L21\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;21\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC21\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;*.sql&amp;quot;</span>: <span class=pl-s>&amp;quot;jinja-sql&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L22\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;22\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC22\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;*.md&amp;quot;</span>: <span class=pl-s>&amp;quot;jinja-md&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L23\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;23\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC23\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-kos>}</span><span class=pl-kos>,</span> </td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L24\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;24\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC24\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;[yaml]&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L25\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;25\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC25\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;editor.defaultFormatter&amp;quot;</span>: <span class=pl-s>&amp;quot;redhat.vscode-yaml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L26\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;26\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC26\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;editor.formatOnSave&amp;quot;</span>: <span class=pl-c1>true</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L27\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;27\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC27\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-kos>}</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L28\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;28\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC28\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;yaml.schemas&amp;quot;</span>: <span class=pl-kos>{</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L29\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;29\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC29\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-s>&amp;quot;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/dbt_yml_files.json&amp;quot;</span>: <span class=pl-kos>[</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L30\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;30\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC30\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;/**/*.yml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L31\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;31\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC31\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;!profiles.yml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L32\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;32\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC32\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;!dbt_project.yml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L33\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;33\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC33\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;!packages.yml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L34\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;34\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC34\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;!selectors.yml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L35\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;35\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC35\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;!profile_template.yml&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L36\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;36\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC36\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-kos>]</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L37\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;37\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC37\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-s>&amp;quot;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/dbt_project.json&amp;quot;</span>: <span class=pl-kos>[</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L38\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;38\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC38\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;dbt_project.yml&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L39\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;39\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC39\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-kos>]</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L40\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;40\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC40\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-s>&amp;quot;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/selectors.json&amp;quot;</span>: <span class=pl-kos>[</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L41\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;41\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC41\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;selectors.yml&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L42\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;42\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC42\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-kos>]</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L43\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;43\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC43\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-s>&amp;quot;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/packages.json&amp;quot;</span>: <span class=pl-kos>[</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L44\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;44\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC44\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>              <span class=pl-s>&amp;quot;packages.yml&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L45\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;45\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC45\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>          <span class=pl-kos>]</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L46\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;46\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC46\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-kos>}</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L47\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;47\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC47\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;workbench.colorTheme&amp;quot;</span>: <span class=pl-s>&amp;quot;GitHub Dark&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L48\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;48\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC48\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-kos>}</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L49\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;49\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC49\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-s>&amp;quot;extensions&amp;quot;</span>: <span class=pl-kos>[</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L50\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;50\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC50\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;innoverio.vscode-dbt-power-user&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L51\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;51\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC51\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;eamodio.gitlens&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L52\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;52\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC52\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;samuelcolvin.jinjahtml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L53\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;53\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC53\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;oderwat.indent-rainbow&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L54\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;54\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC54\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;redhat.vscode-yaml&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L55\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;55\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC55\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;GitHub.github-vscode-theme&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L56\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;56\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC56\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;mechatroner.rainbow-csv&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L57\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;57\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC57\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>        <span class=pl-s>&amp;quot;usernamehw.errorlens&amp;quot;</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L58\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;58\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC58\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>      <span class=pl-kos>]</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L59\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;59\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC59\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>    <span class=pl-kos>}</span> </td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L60\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;60\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC60\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-kos>}</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L61\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;61\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC61\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;initializeCommand&amp;quot;</span>: <span class=pl-s>&amp;quot;echo &amp;#39;Welcome to the DBT development environment!&amp;#39;&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L62\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;62\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC62\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;postCreateCommand&amp;quot;</span>: <span class=pl-s>&amp;quot;python /dev/init/init.py&amp;quot;</span><span class=pl-kos>,</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L63\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;63\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC63\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>  <span class=pl-s>&amp;quot;privileged&amp;quot;</span>: <span class=pl-c1>true</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-devcontainer-json-L64\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;64\&quot;></td>\n          <td id=\&quot;file-devcontainer-json-LC64\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=pl-kos>}</span></td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/2tony2/bafb5e2c543d3255ec7f6262bf211505/raw/279c511d2a87347137dfdfbe16b80d78cdbe7f86/devcontainer.json\&quot; style=\&quot;float:right\&quot; class=\&quot;Link--inTextBlock\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/2tony2/bafb5e2c543d3255ec7f6262bf211505#file-devcontainer-json\&quot; class=\&quot;Link--inTextBlock\&quot;>\n          devcontainer.json\n        </a>\n        hosted with &amp;#10084; by <a class=\&quot;Link--inTextBlock\&quot; href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-5bb00a1034b4.css"><div id="gist128609690" class="gist">
    <div class="gist-file">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-devcontainer-json" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-json-with-comments  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a class="Link--inTextBlock" href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="JSON with Comments" data-tagsearch-path="devcontainer.json">
        <tbody><tr>
          <td id="file-devcontainer-json-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-devcontainer-json-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-devcontainer-json-LC2" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"name"</span>: <span class="pl-s">"dbt dev env"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-devcontainer-json-LC3" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"dockerComposeFile"</span>: <span class="pl-s">"./docker-compose.yml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-devcontainer-json-LC4" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"service"</span>: <span class="pl-s">"local-dbt-env"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-devcontainer-json-LC5" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"runServices"</span>: <span class="pl-kos">[</span><span class="pl-s">"local-dbt-env"</span><span class="pl-kos">]</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L6" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="6"></td>
          <td id="file-devcontainer-json-LC6" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"hostRequirements"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L7" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="7"></td>
          <td id="file-devcontainer-json-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"cpus"</span>: <span class="pl-c1">4</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L8" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="8"></td>
          <td id="file-devcontainer-json-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"memory"</span>: <span class="pl-s">"8gb"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L9" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="9"></td>
          <td id="file-devcontainer-json-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"storage"</span>: <span class="pl-s">"30gb"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L10" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="10"></td>
          <td id="file-devcontainer-json-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-kos">}</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L11" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="11"></td>
          <td id="file-devcontainer-json-LC11" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"workspaceFolder"</span>: <span class="pl-s">"/devcontainer"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L12" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="12"></td>
          <td id="file-devcontainer-json-LC12" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"shutdownAction"</span>: <span class="pl-s">"none"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L13" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="13"></td>
          <td id="file-devcontainer-json-LC13" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"customizations"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L14" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="14"></td>
          <td id="file-devcontainer-json-LC14" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"vscode"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L15" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="15"></td>
          <td id="file-devcontainer-json-LC15" class="blob-code blob-code-inner js-file-line">    <span class="pl-s">"settings"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L16" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="16"></td>
          <td id="file-devcontainer-json-LC16" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"extensions.verifySignature"</span>: <span class="pl-c1">false</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L17" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="17"></td>
          <td id="file-devcontainer-json-LC17" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"python.interpreter.infoVisibility"</span>: <span class="pl-s">"always"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L18" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="18"></td>
          <td id="file-devcontainer-json-LC18" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"python.defaultInterpreterPath"</span>: <span class="pl-s">"/usr/local/bin/python"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L19" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="19"></td>
          <td id="file-devcontainer-json-LC19" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"dbt.dbtPythonPathOverride"</span>: <span class="pl-s">"/usr/local/bin/python"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L20" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="20"></td>
          <td id="file-devcontainer-json-LC20" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"files.associations"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L21" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="21"></td>
          <td id="file-devcontainer-json-LC21" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"*.sql"</span>: <span class="pl-s">"jinja-sql"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L22" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="22"></td>
          <td id="file-devcontainer-json-LC22" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"*.md"</span>: <span class="pl-s">"jinja-md"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L23" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="23"></td>
          <td id="file-devcontainer-json-LC23" class="blob-code blob-code-inner js-file-line">      <span class="pl-kos">}</span><span class="pl-kos">,</span> </td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L24" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="24"></td>
          <td id="file-devcontainer-json-LC24" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"[yaml]"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L25" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="25"></td>
          <td id="file-devcontainer-json-LC25" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"editor.defaultFormatter"</span>: <span class="pl-s">"redhat.vscode-yaml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L26" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="26"></td>
          <td id="file-devcontainer-json-LC26" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"editor.formatOnSave"</span>: <span class="pl-c1">true</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L27" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="27"></td>
          <td id="file-devcontainer-json-LC27" class="blob-code blob-code-inner js-file-line">      <span class="pl-kos">}</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L28" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="28"></td>
          <td id="file-devcontainer-json-LC28" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"yaml.schemas"</span>: <span class="pl-kos">{</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L29" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="29"></td>
          <td id="file-devcontainer-json-LC29" class="blob-code blob-code-inner js-file-line">          <span class="pl-s">"https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/dbt_yml_files.json"</span>: <span class="pl-kos">[</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L30" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="30"></td>
          <td id="file-devcontainer-json-LC30" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"/**/*.yml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L31" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="31"></td>
          <td id="file-devcontainer-json-LC31" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"!profiles.yml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L32" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="32"></td>
          <td id="file-devcontainer-json-LC32" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"!dbt_project.yml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L33" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="33"></td>
          <td id="file-devcontainer-json-LC33" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"!packages.yml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L34" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="34"></td>
          <td id="file-devcontainer-json-LC34" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"!selectors.yml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L35" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="35"></td>
          <td id="file-devcontainer-json-LC35" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"!profile_template.yml"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L36" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="36"></td>
          <td id="file-devcontainer-json-LC36" class="blob-code blob-code-inner js-file-line">          <span class="pl-kos">]</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L37" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="37"></td>
          <td id="file-devcontainer-json-LC37" class="blob-code blob-code-inner js-file-line">          <span class="pl-s">"https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/dbt_project.json"</span>: <span class="pl-kos">[</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L38" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="38"></td>
          <td id="file-devcontainer-json-LC38" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"dbt_project.yml"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L39" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="39"></td>
          <td id="file-devcontainer-json-LC39" class="blob-code blob-code-inner js-file-line">          <span class="pl-kos">]</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L40" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="40"></td>
          <td id="file-devcontainer-json-LC40" class="blob-code blob-code-inner js-file-line">          <span class="pl-s">"https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/selectors.json"</span>: <span class="pl-kos">[</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L41" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="41"></td>
          <td id="file-devcontainer-json-LC41" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"selectors.yml"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L42" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="42"></td>
          <td id="file-devcontainer-json-LC42" class="blob-code blob-code-inner js-file-line">          <span class="pl-kos">]</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L43" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="43"></td>
          <td id="file-devcontainer-json-LC43" class="blob-code blob-code-inner js-file-line">          <span class="pl-s">"https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/packages.json"</span>: <span class="pl-kos">[</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L44" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="44"></td>
          <td id="file-devcontainer-json-LC44" class="blob-code blob-code-inner js-file-line">              <span class="pl-s">"packages.yml"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L45" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="45"></td>
          <td id="file-devcontainer-json-LC45" class="blob-code blob-code-inner js-file-line">          <span class="pl-kos">]</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L46" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="46"></td>
          <td id="file-devcontainer-json-LC46" class="blob-code blob-code-inner js-file-line">      <span class="pl-kos">}</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L47" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="47"></td>
          <td id="file-devcontainer-json-LC47" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"workbench.colorTheme"</span>: <span class="pl-s">"GitHub Dark"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L48" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="48"></td>
          <td id="file-devcontainer-json-LC48" class="blob-code blob-code-inner js-file-line">      <span class="pl-kos">}</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L49" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="49"></td>
          <td id="file-devcontainer-json-LC49" class="blob-code blob-code-inner js-file-line">      <span class="pl-s">"extensions"</span>: <span class="pl-kos">[</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L50" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="50"></td>
          <td id="file-devcontainer-json-LC50" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"innoverio.vscode-dbt-power-user"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L51" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="51"></td>
          <td id="file-devcontainer-json-LC51" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"eamodio.gitlens"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L52" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="52"></td>
          <td id="file-devcontainer-json-LC52" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"samuelcolvin.jinjahtml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L53" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="53"></td>
          <td id="file-devcontainer-json-LC53" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"oderwat.indent-rainbow"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L54" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="54"></td>
          <td id="file-devcontainer-json-LC54" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"redhat.vscode-yaml"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L55" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="55"></td>
          <td id="file-devcontainer-json-LC55" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"GitHub.github-vscode-theme"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L56" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="56"></td>
          <td id="file-devcontainer-json-LC56" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"mechatroner.rainbow-csv"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L57" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="57"></td>
          <td id="file-devcontainer-json-LC57" class="blob-code blob-code-inner js-file-line">        <span class="pl-s">"usernamehw.errorlens"</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L58" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="58"></td>
          <td id="file-devcontainer-json-LC58" class="blob-code blob-code-inner js-file-line">      <span class="pl-kos">]</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L59" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="59"></td>
          <td id="file-devcontainer-json-LC59" class="blob-code blob-code-inner js-file-line">    <span class="pl-kos">}</span> </td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L60" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="60"></td>
          <td id="file-devcontainer-json-LC60" class="blob-code blob-code-inner js-file-line">  <span class="pl-kos">}</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L61" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="61"></td>
          <td id="file-devcontainer-json-LC61" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"initializeCommand"</span>: <span class="pl-s">"echo 'Welcome to the DBT development environment!'"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L62" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="62"></td>
          <td id="file-devcontainer-json-LC62" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"postCreateCommand"</span>: <span class="pl-s">"python /dev/init/init.py"</span><span class="pl-kos">,</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L63" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="63"></td>
          <td id="file-devcontainer-json-LC63" class="blob-code blob-code-inner js-file-line">  <span class="pl-s">"privileged"</span>: <span class="pl-c1">true</span></td>
        </tr>
        <tr>
          <td id="file-devcontainer-json-L64" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="64"></td>
          <td id="file-devcontainer-json-LC64" class="blob-code blob-code-inner js-file-line"><span class="pl-kos">}</span></td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/2tony2/bafb5e2c543d3255ec7f6262bf211505/raw/279c511d2a87347137dfdfbe16b80d78cdbe7f86/devcontainer.json" style="float:right" class="Link--inTextBlock">view raw</a>
        <a href="https://gist.github.com/2tony2/bafb5e2c543d3255ec7f6262bf211505#file-devcontainer-json" class="Link--inTextBlock">
          devcontainer.json
        </a>
        hosted with &#10084; by <a class="Link--inTextBlock" href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p>You can see we are installing the following extenions:</p><ul><li><p><a href="https://marketplace.visualstudio.com/items?itemName=innoverio.vscode-dbt-power-user">innoverio.vscode-dbt-power-user</a> &#8658; This plugin supercharges the local dbt development environment. This adds things like model lineage to your VScode UI.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">eamodio.gitlens</a> &#8658; The free features include an added git blame to each line of code. This allows you to view what commit+author changed a line most recently.</p></li><li><p><a href="https://github.com/features/copilot">GitHub.copilot</a> &#8658; An AI assistant that helps with code generation during development. Requires an active subscription on GitHub.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=dorzey.vscode-sqlfluff">dorzey.vscode-sqlfluff</a> &#8658; A popular open source SQL formatter.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow">oderwat.indent-rainbow</a> &#8658; Adds colored indentation to code to aid in seeing indentation.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml">redhat.vscode-yaml</a> &#8658; allows us to do real time syntax highlighting of our yaml files based on json schemas.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=GitHub.github-vscode-theme">GitHub.github-vscode-theme</a> &#8658; A color theme consistent with GitHub. Adds syntax highlighting similar to GitHub as well. Helps with consistency.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv">mechatroner.rainbow-csv</a> &#8658; Make every column in a CSV a distinct color. This helps with viewing seed files.</p></li><li><p><a href="https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens">usernamehw.errorlens</a> &#8658; Add better visual indication of any formatting issues.</p></li></ul><p>A few things to note about the configuration of this setup:</p><ul><li><p>We can adjust the amount of resources the docker container will be requesting through <code>hostRequirements</code>. Keep in mind that your docker desktop application should be configured to be able to provide these amounts of resources within the settings.</p></li><li><p>The key <code>vscode</code> and then <code>settings</code> defines the <code>settings.json</code> for the dev container environment. Here&#8217;s a breakdown of some important settings</p><ul><li><p><code>"extensions.verifySignature": false</code> &#8658; Some VScode devcontainer environments will have very slow installation steps. (python and pylance can notable be slow). This setting helps to speed things up. Do <strong>NOT</strong> use this with extensions you do not trust.</p></li><li><p><code>"python.interpreter.infoVisibility": "always"</code> &#8658; This tells VScode to always have a python interpreter available. DBT poweruser requires this as it is using constantly running python scripts to provide inputs to the UI elements.</p></li><li><p><code>"python.defaultInterpreterPath": "/usr/local/bin/python"</code> &amp; <code>"dbt.dbtPythonPathOverride": "/usr/local/bin/python"</code> &#8658; This will set the default python interpreter to the python interpreter where we install all of our requirements. This is needed for DBT poweruser to work well.</p></li><li><p><code>"files.associations": { "*.sql": "jinja-sql", "*.md": "jinja-md" },</code> &#8658; This tells VScode to interpret sql and md files as <code>jinja-sql</code> and <code>jinja-md</code> files. DBT poweruser parses files with jinja. Note that we leave out the yml files as is included in the default setup. This is so we can get other YAML functionality in here with the YAML extension.</p></li><li><p><code>"[yaml]": { "editor.defaultFormatter": "redhat.vscode-yaml", "editor.formatOnSave": true</code> &#8658; these are settings for YAMl files. We select the <code>redhad.vscode-yaml</code> extension to interpret yamls as this allows syntax highlighting for yaml files.</p></li><li><p><code>"yaml.schemas": { "&lt;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/dbt_yml_files.json&gt;": [ "/**/*.yml", "!profiles.yml", "!dbt_project.yml", "!packages.yml", "!selectors.yml", "!profile_template.yml" ], "&lt;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/dbt_project.json&gt;": [ "dbt_project.yml" ], "&lt;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/selectors.json&gt;": [ "selectors.yml" ], "&lt;https://raw.githubusercontent.com/dbt-labs/dbt-jsonschema/main/schemas/packages.json&gt;": [ "packages.yml" ] }</code> &#8658; This will configure the yaml plugin to use the officially provided dbt-json schemas for various types of yaml configurations in your dbt project. To view these, check <a href="https://github.com/dbt-labs/dbt-jsonschema">https://github.com/dbt-labs/dbt-jsonschema</a>.</p></li><li><p><code>"initializeCommand": "echo 'Welcome to the DBT development environment!'"</code> &#8658; There&#8217;s a bug in vscode Devcontainers that won&#8217;t start up devcontainers that do not have an init command. You can just add anything in here.</p></li><li><p><code>"postCreateCommand": "python /dev/init/init.py"</code>, We can create a custom post create command that is run after the docker container is created. This is helpful for initializing the environment.</p></li><li><p><code>"privileged": true</code> &#8658; runs the container as root. Do NOT expose this container to the world wide web for your own safety reasons!</p></li></ul></li></ul><h2>Devcontainer env</h2><p>This file can be used to provide environmental variable to the devcontainer similar to how you would add variables to a <code>.bashrc</code> or <code>.zshrc</code> file, for example</p><pre><code><code>MY_VARIABLE='DBT_IS_COOL'
</code></code></pre><p>Would add that environment variable to the devcontainer.</p><h2>Requirements.txt</h2><p>This is a standard python requirements.txt file, feel free to add in any python dependencies that are relevant to your project. This will differ based on what database or data warehouse is connected to your dbt project.</p><h2>Init</h2><p>Scripts used for configuration. Add any scripts here you&#8217;d like to run after a container has been created. This can be used for example to clone a dbt project into the container and run dbt parse in it.</p><h1>The end</h1><p>This was a short introduction to using VScode dev containers for setting up a local development environment for dbt development. This article may be extended in the future. In the mean time, let me know what you like to do for local development with dbt.</p><p>Interesting in more about dbt, data engineering and other topics? Feel free to subscribe, it helps out a ton:<br></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p><h1>Links</h1><p><a href="https://code.visualstudio.com/docs/devcontainers/containers">https://code.visualstudio.com/docs/devcontainers/containers</a></p><p><a href="https://code.visualstudio.com/docs/getstarted/settings#_settingsjson">https://code.visualstudio.com/docs/getstarted/settings#_settingsjson</a></p><p><a href="https://hub.docker.com/_/python">official python image</a></p><p><a href="https://containers.dev/implementors/json_reference/">https://containers.dev/implementors/json_reference/</a></p><p><a href="https://docs.getdbt.com/faqs/Core/install-python-compatibility">https://docs.getdbt.com/faqs/Core/install-python-compatibility</a></p><p><a href="https://github.com/coveooss/json-schema-for-humans">https://github.com/coveooss/json-schema-for-humans</a></p><p><a href="https://github.com/devcontainers/spec/blob/main/schemas/devContainer.base.schema.json">https://github.com/devcontainers/spec/blob/main/schemas/devContainer.base.schema.json</a></p><p><a href="https://containers.dev/overview">https://containers.dev/overview</a></p><p><a href="https://github.com/2tony2/dbt-devcontainer-demo/tree/main/attributes">https://github.com/2tony2/dbt-devcontainer-demo/tree/main/attributes</a></p><p><a href="https://github.com/2tony2/dbt-devcontainer-demo/tree/main">https://github.com/2tony2/dbt-devcontainer-demo/tree/main</a></p><p><a href="https://github.com/dbt-labs/dbt-jsonschema">https://github.com/dbt-labs/dbt-jsonschema</a></p><p><a href="https://marketplace.visualstudio.com/items?itemName=innoverio.vscode-dbt-power-user">https://marketplace.visualstudio.com/items?itemName=innoverio.vscode-dbt-power-user</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Building custom DBT applications with DBT runner]]></title><description><![CDATA[Leveraging the DBT graph for governance]]></description><link>https://www.blog.zelytics.tech/p/building-custom-dbt-applications</link><guid isPermaLink="false">https://www.blog.zelytics.tech/p/building-custom-dbt-applications</guid><dc:creator><![CDATA[Tony Zeljkovic]]></dc:creator><pubDate>Thu, 15 Feb 2024 09:20:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nBmk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.blog.zelytics.tech/subscribe?"><span>Subscribe now</span></a></p><h1>Introduction</h1><h2>Why building in house governance solutions makes sense</h2><p>Many data teams have been leveraging vast troves of data on modern data warehouse platforms like snowflake and databricks. For a lot of these data teams, adopting data build tool (dbt) as their main data transformation management tool was a bliss, especially at smaller project sizes. However, complexity is rising quickly, just observe the growth of dbt project sizes over time:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nBmk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nBmk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 424w, https://substackcdn.com/image/fetch/$s_!nBmk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 848w, https://substackcdn.com/image/fetch/$s_!nBmk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 1272w, https://substackcdn.com/image/fetch/$s_!nBmk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nBmk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png" width="1456" height="808" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:808,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:509120,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nBmk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 424w, https://substackcdn.com/image/fetch/$s_!nBmk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 848w, https://substackcdn.com/image/fetch/$s_!nBmk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 1272w, https://substackcdn.com/image/fetch/$s_!nBmk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F978916b9-92b1-41a0-8ccd-f6e5e4613885_2000x1110.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Fig 1. Number of dbt projects of various sizes over time. source: Coalesce 2023.</strong></figcaption></figure></div><p>This explosive growth of data has turbocharged the need for data observability and governance.</p><p>When it comes to data governance, there are a lot of different goals that companies may want to pursue:</p><ul><li><p>For some companies, proper data protection/data masking is key when subject to GDPR in Europe or HIPPAA/HITECH with medical data in the US.</p></li><li><p>For other companies, getting a grip on their spiraling data warehouse costs may be a key priority</p></li><li><p>Yet other may have a lot of external facing data products that need to have high availability and low error rates in real time</p></li></ul><p>However, addressing these needs with external tooling is challenging.</p><p>Data quality is a vastly different problems to other areas that see more succesful SaaS and PaaS solutions. For example, ETL connectors provided by companies such as FiveTran and Portable solve a well defined problem of ingesting data from one place and deposing it in another. This is a problem that impacts many companies in similar ways, but the problem space for data quality and observability is much more vast and much more dependent on the internals of the company and industry.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VN1M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VN1M!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 424w, https://substackcdn.com/image/fetch/$s_!VN1M!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 848w, https://substackcdn.com/image/fetch/$s_!VN1M!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 1272w, https://substackcdn.com/image/fetch/$s_!VN1M!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VN1M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png" width="1456" height="643" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:643,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1343249,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VN1M!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 424w, https://substackcdn.com/image/fetch/$s_!VN1M!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 848w, https://substackcdn.com/image/fetch/$s_!VN1M!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 1272w, https://substackcdn.com/image/fetch/$s_!VN1M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5dcc0239-2e4b-4cc4-8518-20adb6284573_2374x1048.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">fig 2. Data quality is fuzzy.</figcaption></figure></div><p>When it comes to data governance, there are a <em><strong>lot</strong></em> of different goals that companies may want to pursue:</p><ul><li><p>For some companies, proper data protection/data masking is key when subject to GDPR in Europe or HIPPAA/HITECH with medical data in the US.</p></li><li><p>For other companies, getting a grip on their spiralling data warehouse costs may be a key priority</p></li><li><p>Yet others may have a lot of external facing data products that need to have high availability and low error rates in real time</p></li><li><p>etc&#8230;</p></li></ul><p>In the current economy, we are seeing high interest rates leading to tight budgets and smaller technical team headcount to weather the storm. The last thing a company is waiting for right now is to pay top dollars for data governance platforms that are only solving <strong>SOME</strong> of their problems while paying for the rest of the platform features, many of which this specific company may not need. </p><p>We can see that adoption of tooling in this space is still very early stage:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GvT8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GvT8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 424w, https://substackcdn.com/image/fetch/$s_!GvT8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 848w, https://substackcdn.com/image/fetch/$s_!GvT8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 1272w, https://substackcdn.com/image/fetch/$s_!GvT8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GvT8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png" width="1456" height="1131" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1131,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:426044,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GvT8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 424w, https://substackcdn.com/image/fetch/$s_!GvT8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 848w, https://substackcdn.com/image/fetch/$s_!GvT8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 1272w, https://substackcdn.com/image/fetch/$s_!GvT8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cedbfc3-dc8a-493c-8fb6-648cf95924cd_2000x1554.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Fig 2. Data quality tooling use across industry. Source: state of data 2023.</strong></figcaption></figure></div><p>Considering these things, we are seeing the return of teams building capabilities in house. In such a market environment, it&#8217;s invaluable to be able to deliver custom solutions within the confines of the omnipotent DBT framework.</p><p>In this article series, we will delve deeper into the internal of dbt metadata and how we can leverage that to build governance capabilities for internal data platform teams.</p><p> In this article, we will focus on step 1: The input data.</p><h2>What are DBT artifcats?</h2><p>Whenever you run a dbt command on the CLI, a chain of events is cascaded into the dbt-core backend. One of these events is the production of so called <em>artifcats.</em> In simple terms, these are files containing metadata about the state of your full dbt project.</p><p>There are several different kinds of metadata files, all of which contain metadata from several different aspects of the dbt project. Many of dbt&#8217;s functions such as <code>dbt run</code> or <code>dbt build</code> and their options <code>&#8212;select</code> rely on this backend of data to work properly. The main artifcats produces as of today are:</p><ul><li><p><a href="https://docs.getdbt.com/reference/artifacts/manifest-json">manifest</a>: produced by commands that read and understand your project</p></li><li><p><a href="https://docs.getdbt.com/reference/artifacts/run-results-json">run results</a>: produced by commands that run, compile, or catalog nodes in your DAG</p></li><li><p><a href="https://docs.getdbt.com/reference/artifacts/catalog-json">catalog</a>: produced by&nbsp;<code>docs generate</code></p></li><li><p><a href="https://docs.getdbt.com/reference/artifacts/sources-json">sources</a>: produced by&nbsp;<code>source freshness</code></p></li></ul><p>Understanding what is available in these artifcats and how to work with them is crucial to building custom DBT solutions for managing your data projects.</p><p>To look more in depth into all the available fields for these manifest, please refer to the official JSON schemas provided by dbt <a href="https://schemas.getdbt.com/">https://schemas.getdbt.com/</a>.</p><h1>The DBT manifest and yml schemas</h1><p>In this article, we will specifically focus on the <code>manifest.json</code>, as this is the most important and information rich file in most DBT projects.</p><p>To view the dbt manifest in your project without running any actual models, simply run:</p><pre><code><code>dbt parse</code></code></pre><p>This command will parse all the files in your dbt project and generate a <code>manifest.json</code> in a subfolder of your dbt project called <code>target</code> .</p><p>As of today (manifest version 11) there are the following main top level fields:</p><ul><li><p>metadata</p></li><li><p>nodes</p></li><li><p>sources</p></li><li><p>macros</p></li><li><p>docs</p></li><li><p>exposures</p></li></ul><p>Each of these fields will have their own sub-schema in the json schema. However, the manifest schema can sometimes be a bit tricky to read as theres a lot of available metadata fields for various objects. It&#8217;s usually easier to view some example records in the <code>manifest.json</code> file directly. Here&#8217;s an (simplified) example of a model node from the dbt_facebook_ads repo <a href="https://github.com/fivetran/dbt_facebook_ads/tree/main:">https://github.com/fivetran/dbt_facebook_ads/tree/main:</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!H5mf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!H5mf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 424w, https://substackcdn.com/image/fetch/$s_!H5mf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 848w, https://substackcdn.com/image/fetch/$s_!H5mf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 1272w, https://substackcdn.com/image/fetch/$s_!H5mf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!H5mf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png" width="1456" height="3359" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3359,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:858070,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!H5mf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 424w, https://substackcdn.com/image/fetch/$s_!H5mf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 848w, https://substackcdn.com/image/fetch/$s_!H5mf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 1272w, https://substackcdn.com/image/fetch/$s_!H5mf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed73594-fae4-4c87-97a8-eede154d82e2_1783x4114.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can tell, we have quite a bit of configuration available to us here! You can think of these fields on a higher level falling into four rough categories:</p><ul><li><p>Database details of the model (what database, what schema, what was the query that was run etc&#8230;)</p></li><li><p>Configuration of the individual model. Either derived from configuration blocks in the .<code>sql</code>files, the <code>properties.yml</code> file or project level settings at <code>dbt_project.yml</code> .</p></li><li><p>Relations with other models. This can be parent/daugther relationships, contracts, and other aspects of inter-model relationships.</p></li><li><p>Relation to the dbt project. Think of path of the model file, the unique model id, etc&#8230;</p></li></ul><p>We can parse these fields in several ways to do something actionable with them.</p><h1>Parsing DBT manifest data</h1><p>If you have a decently sized project, taking a look at the <code>manifest.json</code> will quickly make you realise there is a <em><strong>lot</strong></em> of data in there. To start working with this in a more structured way, let&#8217;s explore a couple of different ways in which you may tackle parsing this data.</p><h2>Tackling stuff heads on by parsing the json file</h2><p>The first and most obvious approach you may think of is to tackle the dbt manifest right on with common tools used for json parsing such as command line tools like <code>jq</code> , custom python scripts or using typical data wrangling libraries like pandas. Although it is possible to approach things this way, it is not the route I recommend as it&#8217;s rather detached from using dbt internals.</p><h2>Using the <code>graph</code> variable in dbt macros to parse projects</h2><p>Within the jinja context (<a href="https://docs.getdbt.com/reference/dbt-jinja-functions">nice resource here</a>) of a dbt macro, a lot of the project data can be accessed by working with the <code>graph</code> context variable (<a href="https://docs.getdbt.com/reference/dbt-jinja-functions/graph">see reference here</a>). For a lot of applications, this may be the preferred approach to handling dbt project data, a couple reasons are:</p><ol><li><p>Using a dbt macro allows to use the standard authentication method of your database or data warehouse.</p></li><li><p>By parsing projects in the dbt macro, it can be easier to connect parsing outcome with specific SQL commands in your database/data warehouse.</p></li><li><p>With a macro, it is easier to control the timing of your code execution. A macro may be applied during a model run, a dbt pre-hook or post-hook, or a combination of specific selection criteria (e.g only during a <code>dbt build</code> command).</p></li><li><p>As macros are tightly integrated with how dbt operates, it is easier to integrate any project parsing macro&#8217;s with your projects CI/CD process or add them as hooks in your project.</p></li><li><p>The downside is that it can be complicated to implement non-trivial logic in jinja compared to a fully fledged language such as vanilla python. There&#8217;s only a limited set of python capabilities within this jinja context.</p></li></ol><p>So, how can we use this? Simple, the <code>graph</code> variable contains a dictionary representation of the manifest so we can access it&#8217;s elements just like we would normally do with dictionaries in jinja.</p><p>Let&#8217;s say we want to parse our model data from the manifest, we can simply do this with:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Iff8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Iff8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 424w, https://substackcdn.com/image/fetch/$s_!Iff8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 848w, https://substackcdn.com/image/fetch/$s_!Iff8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 1272w, https://substackcdn.com/image/fetch/$s_!Iff8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Iff8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png" width="768" height="518" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e993d404-920f-4bb7-9279-19cf92f006d2_768x518.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:518,&quot;width&quot;:768,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72182,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Iff8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 424w, https://substackcdn.com/image/fetch/$s_!Iff8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 848w, https://substackcdn.com/image/fetch/$s_!Iff8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 1272w, https://substackcdn.com/image/fetch/$s_!Iff8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe993d404-920f-4bb7-9279-19cf92f006d2_768x518.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As we are accessing the same elements as we may see in a node element in the manifest.json</p><p>Now, let&#8217;s say we would want to parse some metadata tags in the columns of our models, we may do something like:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RPrT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RPrT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 424w, https://substackcdn.com/image/fetch/$s_!RPrT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 848w, https://substackcdn.com/image/fetch/$s_!RPrT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 1272w, https://substackcdn.com/image/fetch/$s_!RPrT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RPrT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png" width="1398" height="358" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/180caa61-4393-421f-a83a-66c3621872ae_1398x358.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:358,&quot;width&quot;:1398,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86270,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RPrT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 424w, https://substackcdn.com/image/fetch/$s_!RPrT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 848w, https://substackcdn.com/image/fetch/$s_!RPrT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 1272w, https://substackcdn.com/image/fetch/$s_!RPrT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180caa61-4393-421f-a83a-66c3621872ae_1398x358.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, this can be quite useful, but it is not the only way to work with the data produced in the manifest.</p><h2>Using the <code>dbtrunner</code> to parse dbt-core objects</h2><p>Since the release of dbt core v1.5, the <code>dbtRunner</code> class has been introduced which allows us to programmatically invoke dbt cli commands and return their <strong>internal</strong> python data classes. This can be used to parse the dbt project in the most powerful way. Some considerations with this approach:</p><ul><li><p>Please read the caveats provided by dbt on the support of these endpoints. The way this works / the values it returns is subject to change in the future <a href="https://docs.getdbt.com/reference/programmatic-invocations#commitments--caveats">https://docs.getdbt.com/reference/programmatic-invocations#commitments--caveats</a></p></li><li><p>This approach can be powerful as the python data classes that are returned contain a lot more fields and objects compared to the dbt manifest. This can allow for the building of a wider array of applications.</p></li><li><p>This is run within standard python and as such has the most flexibility when it comes to programming logic and or the inclusion of other libraries.</p></li><li><p>Because this is using DBT commands more natively, it is able to build applications that more natively support the use of powerful dbt features such as model lineage, selectors and many many more things.</p></li><li><p>Natively picks up any configuration of your dbt project as it&#8217;s running dbt commands in the same way as a cli command would be executed.</p></li></ul><p>As of today, the source code for this implementation can be found in the core library at <code>dbt.cli.main</code> <a href="https://github.com/dbt-labs/dbt-core/blob/9bb970e6ef26907b993d4e51de6dc6ef95fe4aa0/core/dbt/cli/main.py#L61">https://github.com/dbt-labs/dbt-core/blob/9bb970e6ef26907b993d4e51de6dc6ef95fe4aa0/core/dbt/cli/main.py#L61</a>. Let&#8217;s take a look at what we can do with this.</p><h2>Generating a Manifest dataclass object</h2><p>First, let&#8217;s write a simply python script which wil parse our project with <code>dbt parse</code> and return to us a <code>Manifest</code> object.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EA6V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EA6V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 424w, https://substackcdn.com/image/fetch/$s_!EA6V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 848w, https://substackcdn.com/image/fetch/$s_!EA6V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 1272w, https://substackcdn.com/image/fetch/$s_!EA6V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EA6V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png" width="1456" height="807" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:807,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:225311,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EA6V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 424w, https://substackcdn.com/image/fetch/$s_!EA6V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 848w, https://substackcdn.com/image/fetch/$s_!EA6V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 1272w, https://substackcdn.com/image/fetch/$s_!EA6V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d5f17da-0450-4aa2-bf58-85a4a24bf5e8_1802x999.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Running this python script in your project will output the same text to your terminal as when you run <code>dbt parse</code>. It will also yield a manifest file in a similar way at the <code>target</code> folder of your dbt project, but it also returns a much more powerful <code>Manifest</code> object. Let&#8217;s take a look at the source code for this <code>Manifest</code> object to understand better what it can provide to us.</p><p>Under <code>dbt.contracts.graph.manifest.py </code>we can find the class definition <a href="https://github.com/dbt-labs/dbt-core/blob/9bb970e6ef26907b993d4e51de6dc6ef95fe4aa0/core/dbt/contracts/graph/manifest.py#L780">https://github.com/dbt-labs/dbt-core/blob/9bb970e6ef26907b993d4e51de6dc6ef95fe4aa0/core/dbt/contracts/graph/manifest.py#L780</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8gZS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8gZS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 424w, https://substackcdn.com/image/fetch/$s_!8gZS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 848w, https://substackcdn.com/image/fetch/$s_!8gZS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 1272w, https://substackcdn.com/image/fetch/$s_!8gZS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8gZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png" width="1456" height="992" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:992,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:394393,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8gZS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 424w, https://substackcdn.com/image/fetch/$s_!8gZS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 848w, https://substackcdn.com/image/fetch/$s_!8gZS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 1272w, https://substackcdn.com/image/fetch/$s_!8gZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F498e4ab0-6830-4a5d-a77c-77a8ea4f572f_1518x1034.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Wow! That sure is a lot of available data fields.</p><p>You will notice some familar data fields from the dbt manifest such as <code>nodes</code> , <code>sources</code> , <code>macros</code> etc. What you may also notice is that many of these have their own subclasses as well: Nodes are based on <code>ManifestNode</code> , sources are based on <code>SourceDefinition</code> , etc. More interestingly, there are also fields present in this data class that are never defined in the <code>manifest.json</code> . Take a look at <code>files</code> which is based on <code>AnySourceFile</code> . If we delve deeper into it&#8217;s implementation under <code>dbt.contracts.files</code> and try to print some of it&#8217;s data we can actually see a data representation of which <code>yaml</code> and <code>sql</code> files were parsed in the dbt project and the full conent of those yaml and sql files.</p><h2>Parsing subsections of manifest dataclass</h2><p>I hope you start to see some pretty powerful possibilities in here. For example, we can write some pretty simple python code to write a representation that informs us what model data can be associated with available YAML data.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N1m_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N1m_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 424w, https://substackcdn.com/image/fetch/$s_!N1m_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 848w, https://substackcdn.com/image/fetch/$s_!N1m_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 1272w, https://substackcdn.com/image/fetch/$s_!N1m_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N1m_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png" width="1456" height="1783" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1783,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:530502,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!N1m_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 424w, https://substackcdn.com/image/fetch/$s_!N1m_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 848w, https://substackcdn.com/image/fetch/$s_!N1m_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 1272w, https://substackcdn.com/image/fetch/$s_!N1m_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d1e1f14-8a35-477b-a0df-7041a2a2ad51_1752x2145.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This simple transformation yields a dictionary where the key is the model name and the value is the yaml file data, including it&#8217;s full file path, it&#8217;s full definition and much more. The data will look something like below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eeas!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eeas!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 424w, https://substackcdn.com/image/fetch/$s_!eeas!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 848w, https://substackcdn.com/image/fetch/$s_!eeas!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 1272w, https://substackcdn.com/image/fetch/$s_!eeas!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eeas!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png" width="1456" height="1298" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1298,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:790265,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eeas!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 424w, https://substackcdn.com/image/fetch/$s_!eeas!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 848w, https://substackcdn.com/image/fetch/$s_!eeas!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 1272w, https://substackcdn.com/image/fetch/$s_!eeas!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa50fadcd-0a1a-4777-a1be-88f8e59e2203_2000x1783.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>Final words</h1><p>In this article we discussed the value of developing in house governance solutions, the power of dbt artifcats, especially the manifest and discussed various ways of parsing the manifest data for use by downstream applications. In the part, we will focus on an example application which uses this data together with pytest to validate several properties of a dbt project in bulk.</p><h1>Links</h1><ul><li><p><a href="https://state-of-data.com/">https://state-of-data.com/</a></p></li><li><p><a href="https://schemas.getdbt.com/">https://schemas.getdbt.com/</a></p></li><li><p><a href="https://github.com/dbt-labs/dbt-jsonschema/tree/main">https://github.com/dbt-labs/dbt-jsonschema/tree/main</a></p></li><li><p><a href="https://github.com/fivetran/dbt_facebook_ads/tree/main">https://github.com/fivetran/dbt_facebook_ads/tree/main</a></p></li><li><p><a href="https://docs.getdbt.com/reference/dbt-jinja-functions">https://docs.getdbt.com/reference/dbt-jinja-functions</a></p></li><li><p><a href="https://docs.getdbt.com/reference/dbt-jinja-functions/graph">https://docs.getdbt.com/reference/dbt-jinja-functions/graph</a></p></li></ul><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.blog.zelytics.tech/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Tony&#8217;s Substack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item></channel></rss>