<?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:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Coding In Medicine]]></title><description><![CDATA[Coding In Medicine]]></description><link>https://www.codinginmedicine.com/</link><image><url>https://www.codinginmedicine.com/favicon.png</url><title>Coding In Medicine</title><link>https://www.codinginmedicine.com/</link></image><generator>Ghost 4.22</generator><lastBuildDate>Mon, 08 Jun 2026 18:31:09 GMT</lastBuildDate><atom:link href="https://www.codinginmedicine.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Agent-Sourced: A Provenance Tag for the Agent Era]]></title><description><![CDATA[Open source is tearing itself apart over AI contributions: ban them, or drown in them. There's a third answer — label it. I call it agent-sourced.]]></description><link>https://www.codinginmedicine.com/agent-sourced-a-provenance-tag-for-the-agent-era/</link><guid isPermaLink="false">6a26908e5317a40001e87e26</guid><category><![CDATA[Agent-Sourced]]></category><category><![CDATA[AI Engineering]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Mon, 08 Jun 2026 12:55:00 GMT</pubDate><content:encoded><![CDATA[<p><em>This is the short version of an idea I&apos;m putting on record. I make the case more fully on the <a href="https://www.twicedata.com/blog/agent-sourced">TwiceData blog</a>, and in full &#x2014; with the tier criteria, the transition and licensing rules, and a call to codify it in the open &#x2014; in a <a href="https://www.twicedata.com/agent-sourced/">white paper</a>. I&apos;m coining a term here: <strong>agent-sourced</strong>.</em></p><h2 id="the-fight">The fight</h2><p>Open source has a trust problem, and it arrived faster than anyone was ready for. Through 2025 and into 2026, maintainers started drowning. <a href="https://daniel.haxx.se/blog/2026/01/26/the-end-of-the-curl-bug-bounty/">curl ended its bug-bounty program</a> in early 2026 after AI &#x201C;slop&#x201D; overwhelmed its security queue &#x2014; not even one in twenty submissions was a genuine vulnerability. Zig adopted an outright no-LLM policy; Gentoo forbids contributions made with AI tools; NetBSD presumes LLM-generated code &#x201C;tainted&#x201D;; QEMU banned AI contributions on licensing grounds (a policy it&#x2019;s now reconsidering); and GIMP and Flathub banned them outright. LLVM took the opposite tack &#x2014; a human-in-the-loop policy that permits AI-assisted code so long as a person vouches for it.</p><p>It crystallized into a public fight. On one side, DHH: banning AI betrays open source&#x2019;s founding mission &#x2014; everyone&#x2019;s right to change software. On the other, ThePrimeagen: the bans are triage, and quality has to stay with a person. Both are right, which is exactly why the argument doesn&#x2019;t resolve. The frame forces a blunt binary: <strong>ban everything, or drown.</strong></p><h2 id="the-wrong-question">The wrong question</h2><p>&#x201C;Should agents be allowed to contribute&#x201D; is the wrong question. The right one is <em>how their contributions are labeled.</em></p><p>I spend a lot of my time in healthcare data, where provenance is not an abstraction. In clinical and biomedical software, &#x201C;where did this come from, and who checked it&#x201D; is the difference between a number you can act on and one you can&#x2019;t. We already accept that a result is only as trustworthy as its lineage. The code agents are now writing deserves the same treatment &#x2014; not a verdict on whether it&#x2019;s allowed, but an honest label on where it came from.</p><h2 id="agent-sourced">Agent-sourced</h2><blockquote><strong>Agent-sourced</strong> <em>(n., adj.)</em> &#x2014; a change, project, or artifact created mostly autonomously by an agent (one or more, not necessarily a population), with human input extremely low. It is a provenance label, the agent-era analog to <em>crowdsourced</em>: it tells the audience what they&#x2019;re looking at, so the work can be trusted, reviewed, and used accordingly.</blockquote><p>That&#x2019;s the whole move. When the producers of code change, the first thing you owe everyone downstream is honest provenance.</p><h2 id="why-a-label-beats-a-ban-%E2%80%94-and-beats-blind-trust">Why a label beats a ban &#x2014; and beats blind trust</h2><p>A tag does two things at once. It flags the contribution for deeper review, so a maintainer knows exactly where to look harder. And it still lets agent-driven work through &#x2014; welcomed, not forbidden. Honest provenance instead of gatekeeping <em>or</em> blind faith.</p><p>It&#x2019;s also the low-commitment option, which is why it could actually be adopted. Today a maintainer&#x2019;s only moves are expensive: fully review and include a contribution, or ban the whole category. An agent-sourced tag is the lighter middle &#x2014; you neither vet everything nor forbid everyone; you label, and let the label route attention. And crucially, it ships as an add-on, not another bot: a tag on a pull request or commit, <em>not</em> one more AI that fixes issues or reviews PRs. Those add load and noise &#x2014; the very thing maintainers are banning. The tag changes almost nothing in the workflow; it just makes origin legible.</p><h2 id="two-tiers-and-a-gate-that-can%E2%80%99t-be-skipped">Two tiers, and a gate that can&#x2019;t be skipped</h2><p>The useful distinction isn&#x2019;t a long ladder of labels &#x2014; it&#x2019;s two tiers, and the gate between them.</p><p><strong>Tier 1 &#x2014; raw agent-sourced.</strong> The agent&#x2019;s output as submitted, not yet vetted by a person. No one vouches for it. A maintainer can fully ignore it, guilt-free, or browse it when they have time.</p><p><strong>Tier 2 &#x2014; human-verified agent-sourced.</strong> A person has reviewed it and vouches for it &#x2014; but it is <em>still agent-sourced</em>. Verification doesn&#x2019;t erase provenance; both facts travel together (made by an agent, checked by a human). Tier 2 is a required, non-bypassable designator: nothing reaches a release until it has earned it.</p><h2 id="it-honors-both-sides">It honors both sides</h2><p>Agent-sourced code is a double-edged sword, and the tag denies neither edge. It can hide bug-bombs &#x2014; defects that, merged unverified, take weeks to dig out (exactly ThePrimeagen&#x2019;s fear). It can also deliver deep, fast innovation (exactly DHH&#x2019;s hope). The tag validates both: <em>flag it, verify before you trust</em>, and <em>welcome it, don&#x2019;t ban it</em>. In practice the buffer is the fork &#x2014; agent work lives on a tagged fork, quarantined from the base, and when something is genuinely good a human cherry-picks it into the base. The base stays clean, innovation stays free, and a person still holds the gate.</p><h2 id="not-another-bot-%E2%80%94-an-identifier-and-a-verifier">Not another bot &#x2014; an identifier and a verifier</h2><p>Concretely, agent-sourced is two things you can build. First, an <strong>identifier</strong> &#x2014; the provenance tag itself, carried on a commit or pull request: a signed trailer, a label, a field a tool can read. Second, a <strong>verifier / PR framework</strong> &#x2014; the machinery that promotes Tier 1 to Tier 2: who attests, what gets checked, and where the gate sits in the pull-request flow. That&#x2019;s what makes it real rather than rhetorical.</p><h2 id="the-open-question-%E2%80%94-and-an-invitation">The open question &#x2014; and an invitation</h2><p>The honest hard part is governance: who decides what is agent-sourced versus agent-assisted versus human, and who verifies it? The line is genuinely contested &#x2014; and it shouldn&#x2019;t be decreed by any one of us. A real standard would need attestation, a clear boundary between assisted and sourced, transition rules for when a human edits agent work, and licensing terms that travel with the tag &#x2014; and it must be set by <strong>a body of industry leaders</strong>, the way the OSI defined &#x201C;open source,&#x201D; C2PA defined content provenance, and SPDX standardized license identifiers.</p><p>So consider this an invitation. If you maintain a project, steward a foundation, build the agents doing the contributing, or work the licensing side &#x2014; let&#x2019;s convene and define it. The open-source AI fight doesn&#x2019;t have to end with a ban or a flood. It can end with graduated, verifiable trust: agent work welcomed, labeled, and reviewed in proportion to where it came from.</p><h2 id="read-more">Read more</h2><p>A fuller treatment is on the <a href="https://www.twicedata.com/blog/agent-sourced">TwiceData blog</a>, and the complete technical argument &#x2014; tiers, transition, licensing, and the call to codify &#x2014; is the <a href="https://www.twicedata.com/agent-sourced/"><strong>Agent-Sourced white paper</strong></a> (also available as a PDF).</p><p><em>&#x2014; Gyasi Sutton, MD, MPH</em></p>]]></content:encoded></item><item><title><![CDATA[My AI Engineering Philosophy: Why I Never Get Locked In]]></title><description><![CDATA[<h2 id="how-i-learned-this-lesson-the-hard-way">How I Learned This Lesson the Hard Way</h2><p>When OpenAI first launched ChatGPT in November 2022, I was amazed. Here was a GPT-3.5-powered chatbot that could actually hold conversations. When GPT-4 launched in March 2023, I happily signed up for the $20/month Plus plan. It was a bargain</p>]]></description><link>https://www.codinginmedicine.com/my-ai-engineering-philosophy-why-i-never-get-locked-in/</link><guid isPermaLink="false">689a1f759138550001ed7967</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Mon, 11 Aug 2025 17:49:14 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1746286720984-72f386e1872e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDh8fGxsbXxlbnwwfHx8fDE3NTQ5MzQyNTJ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<h2 id="how-i-learned-this-lesson-the-hard-way">How I Learned This Lesson the Hard Way</h2><img src="https://images.unsplash.com/photo-1746286720984-72f386e1872e?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDh8fGxsbXxlbnwwfHx8fDE3NTQ5MzQyNTJ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=2000" alt="My AI Engineering Philosophy: Why I Never Get Locked In"><p>When OpenAI first launched ChatGPT in November 2022, I was amazed. Here was a GPT-3.5-powered chatbot that could actually hold conversations. When GPT-4 launched in March 2023, I happily signed up for the $20/month Plus plan. It was a bargain &#x2014; cutting-edge AI at my fingertips.</p><p>But this wasn&apos;t my first encounter with AI. I&apos;d been working with mostly PyTorch and TensorFlow for some time, training my own models for medical metrics and research. That was the deep learning era &#x2014; open-source frameworks, transparent architectures, and a truly open way of doing things. You trained your own models, you owned your own code, you controlled your own destiny.</p><p>Then ChatGPT happened, and everything shifted. The center moved from open research to vendor-trained models. The term &quot;AI&quot; exploded in popularity, but it meant something different now. Instead of building and training models, we were calling APIs. Instead of understanding architectures, we were optimizing prompts. Instead of owning our models, we were renting them.</p><p>Like everyone else, I followed the &quot;standard&quot; instructions: use OpenAI&apos;s API, optimize prompts for their model, ship fast.</p><p>But then I made what I now consider a rookie mistake: I invested deeply in LangChain, building flows tied to its abstractions. Then model version updates broke things. Same story with Guidance AI, DSPy, and Autogen &#x2014; all great tools that I still keep in my toolkit, but each with its own quirks, dependencies, and upgrade pains.</p><p>It was a wake-up call: the deeper you go into one stack without guardrails, the harder it is to adapt when something changes &#x2014; and in AI, everything changes fast.</p><h2 id="the-trap-most-developers-fall-into">The Trap Most Developers Fall Into</h2><p>Every developer I know has been there. You start with a tool that feels perfect &#x2014; maybe it&apos;s OpenAI, AWS Bedrock, or Google Vertex AI. It works beautifully, you build fast, and you think you&apos;ve found the platform.</p><p>Then one day you realize:</p><ul><li>Your prompts only work with one model.</li><li>Your entire pipeline is bound to one API.</li><li>Your deployment lives and dies on one vendor&apos;s infrastructure.</li></ul><p>That&apos;s vendor lock-in, and it&apos;s the silent killer of AI agility.</p><h2 id="my-philosophy-vendor-neutral-model-agnostic-development">My Philosophy: Vendor-Neutral, Model-Agnostic Development</h2><p>I live by one rule:</p><p><strong>Never build anything that can&apos;t run on any model, any platform, any time.</strong></p><p>Why? Because I&apos;ve been burned &#x2014; and I know how expensive &quot;re-platforming&quot; can be.</p><h3 id="1-models-change-faster-than-you-think">1. Models Change Faster Than You Think</h3><p>Claude, LLaMA, Mistral, and new models launch every month. There are dedicated YouTube channels and major online publications dedicated to the latest releases. If you&apos;re locked to one, you&apos;re already obsolete.</p><h3 id="2-the-wood-and-paper-analogy">2. The Wood and Paper Analogy</h3><p>Think of it this way: if the lowest level of AI capability is like a bunch of 5-year-olds gathering wood pieces, does it take a PhD to do this task? No. But if you need them to use a chipper and process to convert those shavings into paper, that&apos;s when you need an advanced agent and its processing power.</p><p>Simple tasks don&apos;t require advanced AI. But complex processes &#x2014; like converting raw data into structured insights, or orchestrating multi-step workflows &#x2014; absolutely need the processing power of models like Kimi K2 or DeepSeek-R1.</p><p>The problem is that you&apos;re paying premium prices for access to these advanced capabilities, but you don&apos;t own them. You&apos;re renting processing power that could be taken away or changed at any moment.</p><h3 id="3-vendors-change-their-terms">3. Vendors Change Their Terms</h3><p>Prices go up. APIs get deprecated. Features disappear. If you&apos;re locked in, you&apos;re powerless.</p><h2 id="how-this-philosophy-plays-out-in-my-work">How This Philosophy Plays Out in My Work</h2><h3 id="abstraction-layers-everywhere">Abstraction Layers Everywhere</h3><p>I never call a model API directly. I route through an abstraction that can swap models on the fly.</p><p>Litellm goes a long way toward truly unified, model-agnostic calls. I&apos;ve also forked token.js to do the same thing on the js side. Rust has some interesting possibilities in this space for performance-heavy pipelines &#x2014; I&apos;m keeping an eye on it and experimenting where it makes sense.</p><h3 id="prompt-engineering-that-travels">Prompt Engineering That Travels</h3><ul><li>No model-specific hacks</li><li>Structured, portable formats</li><li>Fallback logic for weaker models</li></ul><h3 id="universal-data-formats">Universal Data Formats</h3><ul><li>JSON schemas anyone can consume</li><li>Embeddings from multiple providers</li><li>Vector formats compatible with any DB</li></ul><h2 id="why-medium-sized-businesses-must-train-in-house">Why Medium-Sized Businesses Must Train In-House</h2><p>If you&apos;re running a medium-sized business, building in-house AI capability isn&apos;t a luxury &#x2014; it&apos;s survival insurance.</p><ul><li>You own the models, not just the API keys.</li><li>You keep your IP private.</li><li>You avoid scaling costs that explode as usage grows.</li></ul><p>Small businesses might get by with vendor tools &#x2014; quick to deploy, easy to use &#x2014; but they&apos;re locked into someone else&apos;s feature set. That&apos;s fine for early stage speed, but it&apos;s a trap if you grow.</p><h2 id="the-economics-that-changed-my-mind">The Economics That Changed My Mind</h2><p>At one point, my API and SaaS bills (across OpenAI, Claude, and others) were over $400/month. I run a lot of experiments, and the cost added up fast.</p><p>Now?</p><p>I dedicate half my local storage to open-source models &#x2014; some fine-tuned on synthetic data. My total monthly AI infrastructure cost (all APIs, all SaaS, all cloud) is under $150 &#x2014; with more control, more flexibility, and no lock-in.</p><p>That&apos;s the power of open source. That&apos;s the power of local models. That&apos;s why Chinese open-source LLMs are exploding in popularity &#x2014; no gatekeepers, no monthly ransom, if you have the hardware to run it. There is a race between computer manufacturers and API services that now rent high-capacity GPUs to host open source models.</p><h2 id="the-real-cost-of-vendor-lock-in">The Real Cost of Vendor Lock-In</h2><p>I&apos;ve watched teams waste months migrating to new APIs. I&apos;ve seen products collapse because a vendor killed a feature. I&apos;ve seen developers sidelined because they couldn&apos;t adapt.</p><p>The cost isn&apos;t just technical. It&apos;s existential.</p><h2 id="my-development-principles">My Development Principles</h2><ul><li>Always build abstraction layers &#x2014; APIs are replaceable</li><li>Test with multiple models &#x2014; at least three</li><li>Standardize your formats &#x2014; avoid vendor-only data shapes</li><li>Plan your escape routes &#x2014; migration is inevitable</li><li>Document dependencies &#x2014; know exactly where you&apos;re locked</li></ul><h2 id="the-bottom-line">The Bottom Line</h2><p>Vendor lock-in is death by a thousand paper cuts. It starts with one &quot;quick&quot; API call, and ends with you rewriting your stack to survive.</p><p>The antidote? Build for freedom from day one.</p><ul><li>Freedom to experiment</li><li>Freedom to negotiate</li><li>Freedom to pivot</li><li>Freedom to scale</li></ul><p>Because the best AI systems aren&apos;t the ones that just work today &#x2014; they&apos;re the ones that will still work tomorrow, next year, and in the next wave of change.</p>]]></content:encoded></item><item><title><![CDATA[Manipulating time like a TimeLord with Flux]]></title><description><![CDATA[<p>Testing is a cornerstone of robust software development, but it presents unique challenges when time is a critical factor. How do you verify that a notification is sent exactly 24 hours after an event without making your test suite wait for an entire day? How do you ensure that time-sensitive</p>]]></description><link>https://www.codinginmedicine.com/manipulating-time-like-a-timelord-with-flux-new-draft/</link><guid isPermaLink="false">685e48119138550001ed795d</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Fri, 27 Jun 2025 09:06:47 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1619639572420-e0eac8689c29?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fHBvbGljZSUyMGJveHxlbnwwfHx8fDE3NTEwMTUyOTN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1619639572420-e0eac8689c29?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fHBvbGljZSUyMGJveHxlbnwwfHx8fDE3NTEwMTUyOTN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=2000" alt="Manipulating time like a TimeLord with Flux"><p>Testing is a cornerstone of robust software development, but it presents unique challenges when time is a critical factor. How do you verify that a notification is sent exactly 24 hours after an event without making your test suite wait for an entire day? How do you ensure that time-sensitive logic is immune to the small, unpredictable delays of real-world execution? Mocking Python&apos;s built-in <code>time</code> module can quickly become a tangled mess of patched calls and fragile tests.</p><p>This is precisely where <strong>Flux</strong> comes in. Flux is a Python library designed to give you complete and deterministic control over time in your tests. It allows you to create virtual timelines, making it trivial to fast-forward, freeze, and schedule events without the wait. In this article, we&apos;ll explore how Flux works, dive into real-world use cases, and walk through how to replace unwieldy, time-based tests with elegant, fast, and reliable ones.</p><hr><h2 id="a-bird%E2%80%99s-eye-view-of-flux">A Bird&#x2019;s-Eye View of Flux</h2><p><strong>Flux</strong> is all about giving you <strong>full control over time</strong> in your Python tests and simulations. In a nutshell, it:</p><ol><li><strong>Provides a virtual clock</strong> for your code to run against.</li><li><strong>Allows you to schedule callbacks</strong> to fire at specific points in the virtual timeline.</li><li><strong>Supports time factors</strong>, letting you speed up or slow down how quickly the virtual timeline progresses relative to real-world time.</li><li><strong>Optionally offers a global &#x201C;current timeline&#x201D;</strong> that can transparently replace calls to <code>time.sleep()</code> or <code>time.time()</code> across different modules.</li></ol><p>This means you can test things like &#x201C;what if my function runs for a whole day?&#x201D; without waiting 24 real hours. You can also freeze time for deterministic tests or accelerate time to watch processes play out in a fraction of their usual duration.</p><hr><h2 id="real-world-use-cases">Real-World Use Cases</h2><p>Here are just a few places where Flux can make your life easier:</p><p><strong>Unit Testing Long Waits</strong></p><ul><li>Code that triggers an alert after an hour/day/week can be tested immediately by fast-forwarding the virtual clock.</li></ul><p><strong>Accelerating Simulations</strong></p><ul><li>Got a simulation that&#x2019;s meant to run for days? Crank up the &#x201C;time factor&#x201D; so an hour of virtual time passes in just seconds of real time.</li></ul><p><strong>Freezing Time for Deterministic Tests</strong></p><ul><li>By setting the time factor to zero (or using <code>freeze()</code>), your time-based tests can make exact comparisons without worrying about the overhead of Python or other system delays.</li></ul><p><strong>Scheduling Automated Callbacks</strong></p><ul><li>Want a function to run automatically once the clock hits a certain timestamp? Flux&#x2019;s scheduling mechanism has you covered.</li></ul><p><strong>Seamless Global Integration</strong></p><ul><li>With Flux, you can replace all <code>time</code> module calls in your entire project (or specific modules) with a single global timeline, making your application&#x2019;s notion of time fully under your control.</li></ul><hr><h2 id="hello-flux-your-first-tutorial">Hello, Flux: Your First Tutorial</h2><h3 id="1-installation">1. Installation</h3><p>If Flux is on PyPI or you have it locally, install it with:</p><pre><code class="language-bash">pip install flux</code></pre><p><em>(Or adjust accordingly if you have a different installation process.)</em></p><h3 id="2-meet-timeline">2. Meet <code>Timeline</code></h3><p>Flux offers a class called <code>Timeline</code>. This is the hero of the story&#x2014;an object that represents a virtual clock. Let&#x2019;s see it in action:</p><pre><code class="language-python">
from flux import Timeline

# Create a timeline instance
timeline = Timeline()

# Get the current virtual time
print(f&quot;Current virtual time: {timeline.time()}&quot;)
</code></pre><p>At creation, the timeline starts at a default epoch (similar to the real time&#x2019;s epoch). You can query it just like <code>time.time()</code> in standard Python.</p><h3 id="3-sleeping-virtually">3. Sleeping Virtually</h3><p><code>Timeline.sleep()</code> behaves similarly to <code>time.sleep()</code>, but it advances <em>virtual</em> time:</p><pre><code class="language-python">
print(f&quot;Before sleep: {timeline.time()}&quot;)

# Sleep 10 virtual seconds
timeline.sleep(10)

print(f&quot;After sleep: {timeline.time()}&quot;)
</code></pre><p>By default, s&gt;time factor = 1, so sleeping 10 virtual seconds takes 10 real seconds&#x2014;unless you change the rules.</p><h3 id="4-changing-the-time-factor">4. Changing the Time Factor</h3><p>Think of this like the classic sci-fi or fantasy trope where time moves differently in another dimension&#x2014;five years in Narnia might be only two minutes in the real world. The time factor in Flux gives you that exact power over your code&apos;s timeline. It determines how many virtual seconds pass per real second. For example:</p><pre><code class="language-python">
timeline.set_time_factor(5)
print(f&quot;Time factor: {timeline.get_time_factor()}&quot;)

# Now, sleeping 2 virtual seconds will only take 0.4 real seconds.
timeline.sleep(2)
</code></pre><p>This is a game-changer if you want to speed up or slow down time-dependent logic.</p><h3 id="5-freezing-time">5. Freezing Time</h3><p>Sometimes, you don&#x2019;t want the timeline to progress automatically at all. This is where freezing comes in. When time is frozen (by setting the time factor to 0), <code>timeline.sleep()</code> is the only way to advance the virtual clock, and it does so instantly with no real-world delay.</p><pre><code class="language-python">
timeline.freeze()  # Sets time factor to 0
print(f&quot;Frozen time: {timeline.time()}&quot;)

# Sleeping will instantly advance the virtual clock with no real waiting
timeline.sleep(30)

print(f&quot;Time after &apos;sleeping&apos; on frozen timeline: {timeline.time()}&quot;)
</code></pre><p><strong>Perfect for</strong> avoiding flaky tests caused by unpredictable real-world time offsets.</p><h3 id="6-scheduling-a-callback">6. Scheduling a Callback</h3><p><code>Timeline.schedule_callback(when, callback_function)</code> allows you to set a future point in the virtual timeline to run a function. If you need to wait until all scheduled callbacks have triggered, the library provides a convenient <code>sleep_wait_all_scheduled()</code> method.</p><pre><code class="language-python">
def say_hello():
    print(f&quot;Hello at virtual time: {timeline.time()}&quot;)

timeline.schedule_callback(timeline.time() + 50, say_hello)

timeline.sleep(60)  # The callback fires after we&apos;ve passed the scheduled time
</code></pre><hr><h2 id="seven-practical-code-snippets">Seven Practical Code Snippets</h2><p>Let&#x2019;s walk through how Flux shines in typical situations you might face.</p><h3 id="1-testing-a-long-running-function">1. Testing a Long-Running Function</h3><p>Ever needed to test that a function notifies someone after a day&#x2019;s wait? With Flux, no problem:</p><pre><code class="language-python">
import time

def long_running_func(_sleep=time.sleep, _time=time.time):
    start = _time()
    while True:
        if _time() - start &gt; 60 * 60 * 24:  # 24 hours
            print(&quot;Notification triggered!&quot;)
            break
        _sleep(30)

# Test using a virtual timeline
from flux import Timeline

def test_long_wait():
    timeline = Timeline()
    timeline.set_time_factor(0)  # freeze time to skip real waits

    # After 24 hours + 1 second in virtual time, we expect a notification
    timeline.schedule_callback((60 * 60 * 24) + 1, lambda: None)

    # Run the function with the timeline&apos;s time and sleep
    long_running_func(_sleep=timeline.sleep, _time=timeline.time)

    print(&quot;Test passed without waiting 24 real hours!&quot;)
</code></pre><p>Notice how we never truly wait 24 hours in real-time. The virtual clock leaps to the future instantly.</p><h3 id="2-speeding-up-a-simulation">2. Speeding Up a Simulation</h3><p>Simulations often need to &#x201C;hurry up&#x201D; in test or demo mode. Enter time factor:</p><pre><code class="language-python">
def simulate(duration):
    print(&quot;Simulation started.&quot;)
    time.sleep(duration)
    print(&quot;Simulation ended.&quot;)

from flux import Timeline, current_timeline

def test_simulation_speed():
    # Use the global timeline for convenience
    current_timeline.set(Timeline())
    current_timeline.set_time_factor(1000)

    # If we call simulate(3600), it should take around 3.6s in real time
    simulate(3600)

    print(&quot;Sim finished quickly!&quot;)
</code></pre><h3 id="3-scheduling-periodic-tasks">3. Scheduling Periodic Tasks</h3><p>Want to &#x201C;ping&#x201D; a sensor every 10 virtual seconds, three times in total?</p><pre><code class="language-python">
def sensor_ping():
    print(&quot;Sensor ping at virtual time&quot;)

timeline = Timeline()
timeline.set_time_factor(1)  # Normal speed (just for illustration)

# Schedule pings
for i in range(3):
    timeline.schedule_callback(timeline.time() + 10*(i+1), sensor_ping)

# Sleep long enough for all pings
timeline.sleep(40)

print(&quot;All sensor pings done!&quot;)
</code></pre><h3 id="4-freezing-time-for-precise-assertions">4. Freezing Time for Precise Assertions</h3><p>When time is unfrozen, your code typically runs a few milliseconds slower or faster than you expect. Flux can remove that uncertainty:</p><pre><code class="language-python">
timeline = Timeline()
timeline.freeze()

start = timeline.time()
timeline.sleep(10)
end = timeline.time()

# Perfectly deterministic test
assert (end - start) == 10, &quot;Time delta should be exactly 10!&quot;

print(&quot;Freeze test successful!&quot;)
</code></pre><h3 id="5-using-the-global-timeline-across-modules">5. Using the Global Timeline Across Modules</h3><p>In a large project, you might want multiple modules to share the same timeline. The <code>current_timeline</code> proxy is perfect for this. It allows multiple modules to share the same virtual clock without having to pass the <code>Timeline</code> object around. Here&#x2019;s the pattern:</p><pre><code class="language-python">
# moduleA.py
try:
    from flux import current_timeline as time
except ImportError:
    import time # fallback in case flux is not installed

def do_something_after_a_while():
    time.sleep(100)
    print(&quot;Done!&quot;)

# test_moduleA.py
from flux import Timeline, current_timeline
import moduleA

tl = Timeline()
tl.freeze() # Instantly advance time
current_timeline.set(tl)

moduleA.do_something_after_a_while()
# &quot;Done!&quot; will print immediately
</code></pre><h3 id="6-simulating-a-5-year-stock-prediction-algorithm">6. Simulating a 5-Year Stock Prediction Algorithm</h3><p>The true power of Flux shines when testing complex systems where the outcome isn&#x2019;t predictable by a simple formula. Imagine you&apos;ve built a sophisticated stock prediction algorithm. You need to test how it performs over five years of simulated market data, a process that would be impossible to run in real-time. With Flux, you can validate its long-term behavior in minutes.</p><pre><code class="language-python">
import time
import random

def run_prediction_algo(market_data, duration_days):
    &quot;&quot;&quot;
    A complex function that simulates running a prediction algorithm.
    The logic here would be your proprietary model.
    &quot;&quot;&quot;
    print(&quot;Starting 5-year market prediction simulation...&quot;)
    for day in range(duration_days):
        # Simulate complex daily processing
        # e.g., fetching data, running models, making trades
        _ = [random.random() ** 2 for _ in range(1000)] 
        time.sleep(86400) # Advance one virtual day

    print(&quot;Simulation complete.&quot;)
    return &quot;final_portfolio_value&quot;

# --- Test File ---
from flux import Timeline, current_timeline

def test_five_year_simulation():
    # Set up a global timeline that is frozen to run instantly
    tl = Timeline()
    tl.freeze()
    current_timeline.set(tl)

    five_years_in_days = 365 * 5
    
    # Run the five-year simulation. Since the timeline is frozen,
    # the 1825 calls to sleep(86400) happen instantly.
    result = run_prediction_algo(
        market_data=&quot;mock_data_source&quot;,
        duration_days=five_years_in_days
    )

    # The entire 5-year test completes in a fraction of a real second
    print(f&quot;Test finished. Result from 5-year simulation: {result}&quot;)
    assert result == &quot;final_portfolio_value&quot;

test_five_year_simulation()
</code></pre><h3 id="7-testing-a-cron-like-scheduler">7. Testing a Cron-Like Scheduler</h3><p>How do you test a function that&apos;s supposed to run on a complex schedule, like &quot;every second Friday of the month&quot;? Writing a test that waits for real Fridays to pass is not an option. This is a perfect use case for Flux, pairing it with Python&apos;s `datetime` module to check the logic of the scheduler.</p><pre><code class="language-python">
import datetime
import time

# --- The Function to Test ---
def cleanup_job_runner(get_time):
    &quot;&quot;&quot;
    A runner that executes a cleanup job, but only on the 2nd Friday of any month.
    &quot;&quot;&quot;
    last_run_day = -1
    jobs_fired = 0
    
    # Run for a simulated year
    for _ in range(365):
        now = datetime.datetime.fromtimestamp(get_time())
        
        # Prevent running multiple times on the same day
        if now.day == last_run_day:
            time.sleep(86400) # Move to the next day
            continue

        # Logic: Is it Friday? And is it in the second week of the month?
        is_friday = (now.weekday() == 4)
        is_second_week = (now.day &gt; 7 and now.day &lt;= 14)

        if is_friday and is_second_week:
            print(f&quot;Job fired on {now.strftime(&apos;%Y-%m-%d&apos;)}, the 2nd Friday.&quot;)
            jobs_fired += 1
        
        last_run_day = now.day
        time.sleep(86400) # Move to the next virtual day
        
    return jobs_fired


# --- The Test File ---
from flux import Timeline, current_timeline

def test_cleanup_job_fires_correctly_over_one_year():
    # Start on a known date: Jan 1, 2024 (a Monday)
    tl = Timeline(start_time=1704067200)
    tl.freeze()
    current_timeline.set(tl)

    # Run the scheduler function over a virtual year
    fire_count = cleanup_job_runner(get_time=current_timeline.time)

    print(f&quot;Test complete. The job fired {fire_count} times in a virtual year.&quot;)
    
    # There are 12 months, so the job should fire 12 times in a year.
    assert fire_count == 12

test_cleanup_job_fires_correctly_over_one_year()
</code></pre><hr><h2 id="a-data-engineers-perspective-timezones-and-data-synchronization">A Data Engineer&apos;s Perspective: Timezones and Data Synchronization</h2><p>As a data engineer, one of the most persistent challenges is managing time across distributed systems and diverse data sources. While Flux brilliantly solves the problem of testing time-dependent logic within an application, the real world often introduces a far more chaotic variable: timezones.</p><p>Different databases, APIs, and services often have their own idea of what &apos;now&apos; is. Cloud-based providers are notorious for this, frequently defaulting to regional timestamps (like PST or EST) depending on where a server is located. This can lead to maddening bugs where data seems to arrive out of order or disappears entirely, simply because timestamps aren&apos;t being compared on a level playing field.</p><p><strong>This is why it is an iron-clad best practice to standardize all time data to Coordinated Universal Time (UTC).</strong> By converting every timestamp to UTC as early as possible in your data pipeline, you create a single source of truth. This practice eliminates ambiguity and ensures that when you compare timestamps from a database in Virginia and a log file from Singapore, you&apos;re comparing apples to apples. While Flux helps you control time inside your tests, a strict UTC-first policy will help you tame it in your production systems.</p><hr><h2 id="final-thoughts">Final Thoughts</h2><p>Flux transforms the way you handle time-based tests and simulations. By <strong>mocking time progression</strong>, you sidestep the messy patching of Python&#x2019;s <code>time</code> module in scattered places. You can <strong>freeze time</strong>, <strong>fast-forward</strong> through days in a blink, or <strong>schedule</strong> future events with simple, expressive code.</p><h3 id="key-takeaways">Key Takeaways</h3><ol><li><strong>Easy Setup</strong>: A single <code>Timeline</code> object does everything you need.</li><li><strong>Full Control</strong>: Adjust the time factor, freeze time, or schedule callbacks.</li><li><strong>Save Time</strong>: Test day-long processes in mere seconds (or instantly!).</li><li><strong>Reduce Flakes</strong>: Eliminate the uncertainty of real-world timing.</li><li><strong>Seamless Integration</strong>: Use the global timeline to unify time usage across your codebase.</li></ol><p>With Flux, you&#x2019;ll find testing long or complex time-based scenarios becomes almost trivial&#x2014;no more waiting overnight for tests to pass, and no more dealing with frustrating &#x201C;close enough&#x201D; validations in your assertions.</p><p>So the next time you have a feature that waits hours or days to do something, <strong>consider Flux</strong>. Your future self (and your test suite) will thank you.</p>]]></content:encoded></item><item><title><![CDATA[SQL Alchemy for pythonic pipelines]]></title><description><![CDATA[<p>I&apos;ve primarily been developing code, benchmarks, and data tables in Python, as platforms like Snowflake often present quirks and limitations in data processing that make it challenging to produce the desired deliverables. However, with the recent addition of a new Data Director, I&apos;ve been focusing more</p>]]></description><link>https://www.codinginmedicine.com/sqlalchemy-for-pythonic-pipelines/</link><guid isPermaLink="false">6773fd0b93d63600018e09e9</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Sat, 11 Jan 2025 20:25:03 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1717532973334-0484d7a3bcad?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE5fHxhbGNoZW15fGVufDB8fHx8MTczNTY1NTk5MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1717532973334-0484d7a3bcad?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE5fHxhbGNoZW15fGVufDB8fHx8MTczNTY1NTk5MXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="SQL Alchemy for pythonic pipelines"><p>I&apos;ve primarily been developing code, benchmarks, and data tables in Python, as platforms like Snowflake often present quirks and limitations in data processing that make it challenging to produce the desired deliverables. However, with the recent addition of a new Data Director, I&apos;ve been focusing more on writing SQL queries rather than relying on my usual NumPy and Pandas stack. This shift was motivated by the desire to make the processing code easier to share and understand. Given the complexity of a major project I&apos;m working on, which involves the details I&apos;m outlining here, I feel the need to revisit SQLAlchemy from a beginner&apos;s perspective.</p><h3 id="what-is-sql-alchemy">What is SQL Alchemy</h3><p>SQL Alchemy is a Python library that interacts with relational databases using a high-level Pythonic approach. It provides two main components:</p><ol><li><strong>Core:</strong> A low-level component that offers SQL abstraction and execution.</li><li><strong>ORM (Object Relational Mapper):</strong> A higher-level abstraction that maps Python classes to database tables, enabling developers to interact with the database in terms of objects rather than raw SQL queries.</li></ol><p>SQL Alchemy is one of the most widely used database libraries in Python because of its flexibility, performance, and support for multiple database systems (e.g., SQLite, PostgreSQL, MySQL, Oracle).</p><h3 id="advantages-of-sql-alchemy"><strong>Advantages of SQL Alchemy</strong></h3><ol><li><strong>Database Agnosticism:</strong><br>SQLAlchemy supports multiple database engines, so you can easily switch between databases (e.g., SQLite, MySQL, PostgreSQL) by changing the connection string.</li><li><strong>ORM Abstraction:</strong><br>SQLAlchemy&#x2019;s ORM lets you work with Python objects instead of writing raw SQL, making the code cleaner and easier to maintain.</li><li><strong>SQLAlchemy Core:</strong><br>Provides flexibility for advanced users to write custom SQL queries if the ORM does not fit a particular use case.</li><li><strong>Ease of Use with Relationships:</strong><br>SQLAlchemy makes defining and managing relationships between tables intuitive through Python objects.</li><li><strong>Query Composition:</strong><br>You can build queries dynamically using Python expressions, making complex query construction more manageable.</li><li><strong>Better Security:</strong><br>It handles SQL injection prevention automatically by using parameterized queries.</li><li><strong>Scalability and Performance:</strong><br>SQLAlchemy uses connection pooling and efficient query generation to work well in high-performance scenarios.</li></ol><h3 id="differences-between-sqlalchemy-and-straight-sql"><strong>Differences Between SQLAlchemy and Straight SQL</strong></h3><!--kg-card-begin: html--><table><thead><tr><th><strong>Feature</strong></th><th><strong>SQLAlchemy</strong></th><th><strong>Straight SQL</strong></th></tr></thead><tbody><tr><td><strong>Abstraction</strong></td><td>Provides Pythonic abstraction over SQL, especially with the ORM.</td><td>Requires writing raw SQL queries for all interactions.</td></tr><tr><td><strong>Database Agnosticism</strong></td><td>Supports multiple database engines without changing code structure.</td><td>SQL queries are typically specific to a database engine.</td></tr><tr><td><strong>Ease of Relationships</strong></td><td>Relationships between tables are handled with Python objects and defined declaratively.</td><td>Relationships must be handled explicitly in SQL.</td></tr><tr><td><strong>Code Readability</strong></td><td>Queries are more readable and integrated into Python&apos;s syntax.</td><td>SQL queries are separate and less Pythonic.</td></tr><tr><td><strong>Complex Query Building</strong></td><td>Queries can be built dynamically using Python.</td><td>Queries must be written explicitly in SQL.</td></tr><tr><td><strong>Security</strong></td><td>Automatically escapes parameters to prevent SQL injection.</td><td>Requires manual handling to prevent SQL injection.</td></tr><tr><td><strong>Performance Tuning</strong></td><td>Supports features like connection pooling and lazy loading.</td><td>Performance tuning requires manual effort and expertise.</td></tr></tbody></table><!--kg-card-end: html--><hr><h3 id="examples-sqlalchemy-vs-straight-sql"><strong>Examples: SQLAlchemy vs. Straight SQL</strong></h3><h4 id="example-1-fetching-data">Example 1: Fetching Data</h4><ul><li><strong>Straight SQL</strong></li></ul><pre><code>import sqlite3

connection = sqlite3.connect(&apos;example.db&apos;)
cursor = connection.cursor()

# Execute a raw SQL query
cursor.execute(&quot;SELECT * FROM users WHERE age &gt; ?&quot;, (25,))
results = cursor.fetchall()

for row in results:
    print(row)

connection.close()
</code></pre><ul><li><strong>SQLAlchemy</strong></li></ul><pre><code>from sqlalchemy import create_engine, Table, MetaData
from sqlalchemy.orm import sessionmaker

# Create database engine and session
engine = create_engine(&apos;sqlite:///example.db&apos;)
Session = sessionmaker(bind=engine)
session = Session()

# ORM Example
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = &apos;users&apos;
    id = Column(Integer, primary_key=True)
    name = Column(String)
    age = Column(Integer)

# Query using ORM
results = session.query(User).filter(User.age &gt; 25).all()
for user in results:
    print(user.name, user.age)

# Alternatively, using Core
metadata = MetaData(bind=engine)
users_table = Table(&apos;users&apos;, metadata, autoload_with=engine)
query = users_table.select().where(users_table.c.age &gt; 25)
connection = engine.connect()
results = connection.execute(query)

for row in results:
    print(row)
</code></pre><h4 id="example-2-inserting-data">Example 2: Inserting Data</h4><ul><li><strong>Straight SQL</strong></li></ul><pre><code>connection = sqlite3.connect(&apos;example.db&apos;)
cursor = connection.cursor()

# Insert a record
cursor.execute(&quot;INSERT INTO users (name, age) VALUES (?, ?)&quot;, (&apos;Alice&apos;, 30))
connection.commit()
connection.close()
</code></pre><ul><li><strong>SQLAlchemy</strong></li></ul><pre><code># ORM Example
new_user = User(name=&apos;Alice&apos;, age=30)
session.add(new_user)
session.commit()

# Alternatively, using Core
insert_query = users_table.insert().values(name=&apos;Alice&apos;, age=30)
connection = engine.connect()
connection.execute(insert_query)
</code></pre><h4 id="example-3-relationships-between-tables">Example 3: Relationships Between Tables</h4><ul><li><strong>Straight SQL</strong></li></ul><pre><code>-- Example SQL
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INTEGER, description TEXT,
                     FOREIGN KEY(user_id) REFERENCES users(id));

SELECT users.name, orders.description
FROM users
JOIN orders ON users.id = orders.user_id;
</code></pre><ul><li><strong>SQLAlchemy</strong></li></ul><pre><code>from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

class Order(Base):
    __tablename__ = &apos;orders&apos;
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey(&apos;users.id&apos;))
    description = Column(String)
    user = relationship(&quot;User&quot;, back_populates=&quot;orders&quot;)

User.orders = relationship(&quot;Order&quot;, order_by=Order.id, back_populates=&quot;user&quot;)

# Querying
results = session.query(User).join(User.orders).filter(Order.description == &apos;Some order&apos;).all()
for user in results:
    print(user.name)
</code></pre><hr><h3 id="when-to-use-sqlalchemy-vs-straight-sql"><strong>When to Use SQLAlchemy vs. Straight SQL</strong></h3><p>Use <strong>SQLAlchemy</strong>:</p><ul><li>When you need portability across different databases.</li><li>When the project requires object-oriented, maintainable code.</li><li>When you&#x2019;re building complex applications with relationships.</li></ul><p>Use <strong>Straight SQL</strong>:</p><ul><li>When performance is critical, you can optimize raw queries.</li><li>For simple scripts or one-off database operations.</li><li>When you need to execute non-standard SQL specific to the database engine.</li></ul><p>SQLAlchemy provides a balance between flexibility and abstraction, making it an excellent choice for most Python projects that involve databases.</p><h3 id="two-different-paths-to-sqlalchemy">Two different paths to SQLAlchemy</h3><p>SQLAlchemy provides two distinct ways to interact with a database: <strong>ORM (Object Relational Mapper)</strong> using <strong>classes</strong> and <strong>Core</strong> using <strong>tables</strong>. Both approaches are powerful and suited to different use cases. Here&#x2019;s an explanation of the differences between declaring classes in SQLAlchemy ORM and using the Core approach, with examples to clarify.</p><h3 id="1-declaring-classes-sqlalchemy-orm"><strong>1. Declaring Classes (SQLAlchemy ORM)</strong></h3><p>When using SQLAlchemy ORM, you define database tables as Python classes. These classes are mapped to database tables whose attributes represent the table&#x2019;s columns.</p><h4 id="how-it-works"><strong>How It Works:</strong></h4><ul><li>Classes are declared using the <code>declarative_base()</code> class or the <code>Declarative Base</code> system.</li><li>Each class represents a table in the database.</li><li>Relationships between tables are defined using Python attributes and <code>ForeignKey</code> or <code>relationship</code>.</li></ul><h4 id="advantages"><strong>Advantages:</strong></h4><ul><li><strong>Object-Oriented Approach:</strong> Work directly with Python objects, which is more intuitive for many developers.</li><li><strong>Ease of Use:</strong> Queries and relationships are handled in terms of objects, simplifying code.</li><li><strong>Abstraction:</strong> Abstracts away SQL queries, making it easier to focus on business logic.</li></ul><h4 id="example"><strong>Example:</strong></h4><pre><code>from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import declarative_base, relationship, sessionmaker

# Declare a base class
Base = declarative_base()

# Define User and Order classes (tables)
class User(Base):
    __tablename__ = &apos;users&apos;
    id = Column(Integer, primary_key=True)
    name = Column(String)

    # Relationship to orders
    orders = relationship(&apos;Order&apos;, back_populates=&apos;user&apos;)


class Order(Base):
    __tablename__ = &apos;orders&apos;
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey(&apos;users.id&apos;))
    description = Column(String)

    user = relationship(&apos;User&apos;, back_populates=&apos;orders&apos;)

# Create tables and add data
engine = create_engine(&apos;sqlite:///example.db&apos;)
Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

new_user = User(name=&apos;Alice&apos;, orders=[Order(description=&apos;Order 1&apos;)])
session.add(new_user)
session.commit()

# Querying
user = session.query(User).filter_by(name=&apos;Alice&apos;).first()
print(user.orders[0].description)  # Output: Order 1
</code></pre><h3 id="2-using-core-table-based"><strong>2. Using Core (Table-Based)</strong></h3><p>In SQLAlchemy Core, you define tables explicitly using the <code>Table</code> class. Instead of objects, you work with raw SQL expressions and the table objects directly.</p><h4 id="how-it-works-1"><strong>How It Works:</strong></h4><ul><li>Tables are declared using the <code>Table</code> class.</li><li>SQL queries are built using SQLAlchemy&#x2019;s expression language.</li><li>No direct Python object representation exists for database rows; results are just dictionaries or tuples.</li></ul><h4 id="advantages-1"><strong>Advantages:</strong></h4><ul><li><strong>Flexibility:</strong> Gives you more control over raw SQL queries.</li><li><strong>Performance:</strong> No ORM overhead; you work directly with SQL and table definitions.</li><li><strong>Minimalism:</strong> Useful for simple scripts or scenarios where an ORM is unnecessary.</li></ul><h4 id="example-1"><strong>Example:</strong></h4><pre><code>from sqlalchemy import Table, Column, Integer, String, ForeignKey, MetaData, create_engine

# Define tables
metadata = MetaData()

users = Table(
    &apos;users&apos;, metadata,
    Column(&apos;id&apos;, Integer, primary_key=True),
    Column(&apos;name&apos;, String)
)

orders = Table(
    &apos;orders&apos;, metadata,
    Column(&apos;id&apos;, Integer, primary_key=True),
    Column(&apos;user_id&apos;, Integer, ForeignKey(&apos;users.id&apos;)),
    Column(&apos;description&apos;, String)
)

# Create tables and add data
engine = create_engine(&apos;sqlite:///example.db&apos;)
metadata.create_all(engine)

# Insert data
with engine.connect() as conn:
    conn.execute(users.insert().values(name=&apos;Alice&apos;))
    conn.execute(orders.insert().values(user_id=1, description=&apos;Order 1&apos;))

# Querying
with engine.connect() as conn:
    result = conn.execute(users.select().where(users.c.name == &apos;Alice&apos;))
    for row in result:
        print(row)  # Output: (1, &apos;Alice&apos;)
</code></pre><h3 id="key-differences-between-declaring-classes-orm-and-core"><strong>Key Differences Between Declaring Classes (ORM) and Core</strong></h3><!--kg-card-begin: html--><table><thead><tr><th><strong>Aspect</strong></th><th><strong>Declaring Classes (ORM)</strong></th><th><strong>Core (Table-Based)</strong></th></tr></thead><tbody><tr><td><strong>Representation</strong></td><td>Python classes represent database tables.</td><td>Explicit <code>Table</code> objects represent database tables.</td></tr><tr><td><strong>Data Access</strong></td><td>Returns objects with attributes (e.g., <code>user.name</code>).</td><td>Returns rows as dictionaries or tuples (e.g., <code>row[&apos;name&apos;]</code>).</td></tr><tr><td><strong>Relationships</strong></td><td>Handled via <code>relationship()</code> and <code>ForeignKey</code>.</td><td>Handled explicitly via joins in SQL.</td></tr><tr><td><strong>Query Syntax</strong></td><td>High-level, object-oriented queries (e.g., <code>session.query(User).filter(...)</code>).</td><td>Low-level, SQL-like queries (e.g., <code>users.select().where(...)</code>).</td></tr><tr><td><strong>Flexibility</strong></td><td>Abstracts SQL; better for simpler or object-heavy use cases.</td><td>Offers fine-grained control for custom or complex queries.</td></tr><tr><td><strong>Performance</strong></td><td>Slightly slower due to ORM overhead.</td><td>Faster due to the absence of an ORM layer.</td></tr><tr><td><strong>Learning Curve</strong></td><td>Easier for Python developers, but adds abstraction.</td><td>Requires more knowledge of SQL and the Core API.</td></tr><tr><td><strong>Use Case</strong></td><td>Complex applications with many relationships.</td><td>Simple scripts or scenarios requiring precise SQL control.</td></tr></tbody></table><!--kg-card-end: html--><h3 id="when-to-use-which"><strong>When to Use Which?</strong></h3><p><strong>Use ORM (Classes):</strong></p><ul><li>When your application involves complex relationships between tables.</li><li>When working with Python objects fits naturally with the problem domain.</li><li>When you want to reduce boilerplate and make your code more Pythonic.</li></ul><p><strong>Use Core:</strong></p><ul><li>When you need fine-grained control over SQL queries.</li><li>For performance-critical scenarios where ORM overhead is unacceptable.</li><li>When you need flexibility to execute complex or database-specific queries.</li></ul><h3 id="blending-orm-and-core"><strong>Blending ORM and Core</strong></h3><p>You can also mix the two approaches in SQLAlchemy. For example, you might define tables using Core but use ORM for parts of the application.</p><pre><code># Define a table using Core
users = Table(
    &apos;users&apos;, metadata,
    Column(&apos;id&apos;, Integer, primary_key=True),
    Column(&apos;name&apos;, String)
)

# Map the table to an ORM class
from sqlalchemy.orm import mapper

class User:
    pass

mapper(User, users)

# Now you can use the ORM with the mapped class
session.add(User(name=&apos;Alice&apos;))
</code></pre><h2 id="other-industry-standard-data-engines">Other Industry Standard Data Engines</h2><p>Using less common data engines like <strong>Snowflake</strong> or other database systems with SQLAlchemy requires leveraging its <strong>database-agnostic architecture</strong>. SQLAlchemy supports a wide range of database engines through <strong>dialects</strong>, which are plugins that enable communication with specific databases. Snowflake, for instance, has a dedicated SQLAlchemy dialect.</p><p>Here&#x2019;s how you can use SQLAlchemy with non-common databases like Snowflake or others, including any nuances or key considerations.</p><h3 id="1-snowflake-with-sqlalchemy"><strong>1. Snowflake with SQLAlchemy</strong></h3><h4 id="setup"><strong>Setup</strong></h4><p>To connect SQLAlchemy to Snowflake, you need the <strong>Snowflake SQLAlchemy dialect</strong>. Install the required libraries:</p><pre><code>pip install snowflake-sqlalchemy
</code></pre><h4 id="connection-setup"><strong>Connection Setup</strong></h4><p>Here&#x2019;s how you can connect SQLAlchemy to a Snowflake database:</p><pre><code>from sqlalchemy import create_engine

# Snowflake connection string
engine = create_engine(
    &apos;snowflake://{user}:{password}@{account}/{database}/{schema}&apos;.format(
        user=&apos;YOUR_USER&apos;,
        password=&apos;YOUR_PASSWORD&apos;,
        account=&apos;YOUR_ACCOUNT&apos;,
        database=&apos;YOUR_DATABASE&apos;,
        schema=&apos;YOUR_SCHEMA&apos;
    )
)

# Test connection
connection = engine.connect()
result = connection.execute(&quot;SELECT CURRENT_VERSION()&quot;)
for row in result:
    print(row)
connection.close()
</code></pre><p>Using ORM with Snowflake</p><pre><code>from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

# Define a table using ORM
class Employee(Base):
    __tablename__ = &apos;employees&apos;
    id = Column(Integer, primary_key=True)
    name = Column(String)
    salary = Column(Integer)

# Bind engine and create tables
Base.metadata.create_all(engine)

# Insert data
Session = sessionmaker(bind=engine)
session = Session()
new_employee = Employee(name=&quot;Alice&quot;, salary=100000)
session.add(new_employee)
session.commit()

# Query data
employees = session.query(Employee).all()
for employee in employees:
    print(employee.name, employee.salary)
</code></pre><p>Using Core with Snowflake</p><pre><code>from sqlalchemy import Table, MetaData, Column, Integer, String

metadata = MetaData()

# Define the table
employees = Table(
    &apos;employees&apos;, metadata,
    Column(&apos;id&apos;, Integer, primary_key=True),
    Column(&apos;name&apos;, String),
    Column(&apos;salary&apos;, Integer)
)

# Create the table in Snowflake
metadata.create_all(engine)

# Insert data
with engine.connect() as conn:
    conn.execute(employees.insert().values(name=&apos;Alice&apos;, salary=100000))

# Query data
with engine.connect() as conn:
    results = conn.execute(employees.select())
    for row in results:
        print(row)
</code></pre><h3 id="2-general-approach-for-other-databases"><strong>2. General Approach for Other Databases</strong></h3><p>For other databases, SQLAlchemy relies on a specific <strong>dialect</strong>. Here&apos;s how to adapt to various data engines:</p><h4 id="steps"><strong>Steps:</strong></h4><p><strong>Install the Dialect for the Database:</strong><br>Search for a SQLAlchemy-compatible dialect for your database. Many major databases have official dialects, while others have community-maintained ones.</p><p>Examples:</p><ul><li><strong>MongoDB</strong>: <code>pip install sqlalchemy-mongo</code></li><li><strong>ClickHouse</strong>: <code>pip install clickhouse-sqlalchemy</code></li><li><strong>BigQuery</strong>: <code>pip install pybigquery</code></li></ul><ol><li><strong>Find the Connection String Format:</strong><br>Check the dialect documentation for the correct connection string format. Each database has unique requirements, such as authentication details or specific parameters.</li><li><strong>Use SQLAlchemy&apos;s Core or ORM:</strong><br>Use the same <code>create_engine()</code> syntax and define tables or ORM classes as needed.</li></ol><hr><h3 id="examples-of-other-databases"><strong>Examples of Other Databases</strong></h3><h4 id="mongodb-with-sqlalchemy-mongo"><strong>MongoDB (with SQLAlchemy-mongo)</strong></h4><p>While MongoDB is a NoSQL database, some projects provide an SQL-like interface for MongoDB.</p><pre><code>from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer

# Install MongoDB dialect first: pip install sqlalchemy-mongo
engine = create_engine(&apos;mongodb://localhost:27017/mydatabase&apos;)
metadata = MetaData()

# Define a table-like structure
users = Table(
    &apos;users&apos;, metadata,
    Column(&apos;id&apos;, Integer, primary_key=True),
    Column(&apos;name&apos;, String),
    Column(&apos;age&apos;, Integer)
)

# Insert and query data
with engine.connect() as conn:
    conn.execute(users.insert().values(id=1, name=&apos;Alice&apos;, age=30))
    result = conn.execute(users.select())
    for row in result:
        print(row)
</code></pre><h4 id="clickhouse"><strong>ClickHouse</strong></h4><p>ClickHouse is a fast columnar database for analytical queries.</p><pre><code>from sqlalchemy import create_engine, Table, MetaData, Column, Integer, String

# Install ClickHouse dialect first: pip install clickhouse-sqlalchemy
engine = create_engine(&apos;clickhouse://default:@localhost/test&apos;)
metadata = MetaData()

# Define a table
users = Table(
    &apos;users&apos;, metadata,
    Column(&apos;id&apos;, Integer, primary_key=True),
    Column(&apos;name&apos;, String),
    Column(&apos;age&apos;, Integer)
)

# Create the table in ClickHouse
metadata.create_all(engine)

# Insert and query data
with engine.connect() as conn:
    conn.execute(users.insert().values(id=1, name=&apos;Alice&apos;, age=30))
    results = conn.execute(users.select())
    for row in results:
        print(row)
</code></pre><h4 id="google-bigquery"><strong>Google BigQuery</strong></h4><p>BigQuery works with SQLAlchemy via the <code>pybigquery</code> dialect.</p><pre><code>from sqlalchemy import create_engine

# Install BigQuery dialect: pip install pybigquery
engine = create_engine(&apos;bigquery://project_id/dataset&apos;)

# Query BigQuery
with engine.connect() as conn:
    result = conn.execute(&quot;SELECT * FROM my_table LIMIT 10&quot;)
    for row in result:
        print(row)
</code></pre><h3 id="key-considerations-for-non-common-data-engines"><strong>Key Considerations for Non-Common Data Engines</strong></h3><ol><li><strong>Install the Correct Dialect:</strong><br>Ensure the dialect matches your database engine. For some niche engines, the dialect might not be actively maintained, so check compatibility with SQLAlchemy&#x2019;s current version.</li><li><strong>Understand Database-Specific Features:</strong><br>Some databases (e.g., Snowflake, ClickHouse) have unique capabilities like columnar storage or serverless queries. SQLAlchemy&#x2019;s Core can often handle these features better than ORM.</li><li><strong>Performance Tuning:</strong><br>For large-scale or analytical databases (e.g., Snowflake, BigQuery), batch inserts and asynchronous connections (using libraries like <code>asyncio</code>) can improve performance.</li><li><strong>Custom SQL:</strong><br>For specialized databases, you might need to write raw SQL queries when SQLAlchemy abstractions fall short. Use SQLAlchemy&#x2019;s <code>text()</code> for this purpose.</li></ol><h3 id="fallback-raw-sql-examples-in-sqlalchemy"><strong>Fallback Raw SQL Examples in SQLAlchemy</strong></h3><p>When working with non-common data engines, certain scenarios may require raw SQL queries to leverage database-specific features or handle operations that SQLAlchemy&#x2019;s abstractions don&#x2019;t natively support. SQLAlchemy allows you to execute raw SQL through the <code>text()</code> function, which provides full flexibility to write and execute custom queries.</p><p>Here are two examples of using raw SQL with SQLAlchemy:</p><h4 id="example-1-custom-query-for-analytical-databases-eg-snowflake-bigquery"><strong>Example 1: Custom Query for Analytical Databases (e.g., Snowflake, BigQuery)</strong></h4><p>In analytical databases, you might need to use specialized SQL features, such as window functions or partitioning, that are not straightforward to implement with SQLAlchemy&#x2019;s ORM or Core.</p><pre><code>from sqlalchemy import create_engine, text

# Connect to the database
engine = create_engine(
    &apos;snowflake://{user}:{password}@{account}/{database}/{schema}&apos;.format(
        user=&apos;YOUR_USER&apos;,
        password=&apos;YOUR_PASSWORD&apos;,
        account=&apos;YOUR_ACCOUNT&apos;,
        database=&apos;YOUR_DATABASE&apos;,
        schema=&apos;YOUR_SCHEMA&apos;
    )
)

# Write and execute a custom SQL query
query = text(&quot;&quot;&quot;
    SELECT 
        department, 
        COUNT(employee_id) AS total_employees,
        AVG(salary) AS avg_salary
    FROM employees
    WHERE hire_date &gt;= :start_date
    GROUP BY department
    ORDER BY avg_salary DESC
&quot;&quot;&quot;)

# Execute the query and pass parameters
with engine.connect() as conn:
    result = conn.execute(query, {&quot;start_date&quot;: &quot;2022-01-01&quot;})
    for row in result:
        print(row)

</code></pre><h4 id="example-2-bulk-data-insertion-using-text"><strong>Example 2: Bulk Data Insertion Using <code>text()</code></strong></h4><p>For databases optimized for high-volume data processing, such as ClickHouse or Snowflake, you might want to perform bulk inserts directly using raw SQL.</p><pre><code>from sqlalchemy import create_engine, text

# Connect to the database
engine = create_engine(&apos;clickhouse://default:@localhost/test&apos;)

# Define raw SQL for bulk insertion
bulk_insert_sql = text(&quot;&quot;&quot;
    INSERT INTO users (id, name, age)
    VALUES 
        (:id1, :name1, :age1),
        (:id2, :name2, :age2),
        (:id3, :name3, :age3)
&quot;&quot;&quot;)

# Data to be inserted
data = {
    &quot;id1&quot;: 1, &quot;name1&quot;: &quot;Alice&quot;, &quot;age1&quot;: 30,
    &quot;id2&quot;: 2, &quot;name2&quot;: &quot;Bob&quot;, &quot;age2&quot;: 25,
    &quot;id3&quot;: 3, &quot;name3&quot;: &quot;Charlie&quot;, &quot;age3&quot;: 35
}

# Execute the raw SQL
with engine.connect() as conn:
    conn.execute(bulk_insert_sql, data)

# Verify the insertion
select_query = text(&quot;SELECT * FROM users&quot;)
with engine.connect() as conn:
    result = conn.execute(select_query)
    for row in result:
        print(row)
</code></pre><p>Using <code>text()</code> with raw SQL gives you complete control when SQLAlchemy abstractions are not enough, while still benefiting from connection pooling and parameterized queries for security and performance.. Of note raw queries can utilize native features of the data engines--for example--time travel in Snowflake</p><h3 id="conclusion"><strong>Conclusion</strong></h3><p>As we&apos;ve explored, SQLAlchemy is a versatile tool that offers a Pythonic approach to managing databases, providing both ORM and Core interfaces for different use cases. While its abstractions make working with relational databases cleaner and more intuitive, certain scenarios, especially when working with less common data engines like Snowflake, ClickHouse, or BigQuery, may still require fallback raw SQL queries to unlock engine-specific features.</p><p><strong>Use Cases May Vary:</strong></p><ul><li>If your goal is to <strong>avoid database-specific errors</strong> and ensure portability, SQLAlchemy&apos;s ORM and Core provide excellent abstraction layers, making it easier to share and maintain code.</li><li>On the other hand, when you want to <strong>lock down pipeline logic</strong> and leverage the full power of a specific database&apos;s unique features (like Snowflake&apos;s time travel or BigQuery&apos;s partitioned tables), raw SQL combined with SQLAlchemy&apos;s <code>text()</code> function offers the flexibility you need.</li></ul><p><strong>A Primer for Experimentation:</strong><br>If you&#x2019;re new to SQLAlchemy, think of this article as a primer to help you get started. Dive into the ORM to handle objects and relationships intuitively, experiment with Core for raw control, and don&apos;t hesitate to mix in <code>text()</code> queries when needed. The flexibility of SQLAlchemy allows you to balance simplicity with power, scaling up as your needs evolve.</p><p>Ultimately, SQLAlchemy is a foundation for building robust, maintainable pipelines in Python. Its ability to combine high-level abstractions with low-level control makes it a critical tool for any data engineer or developer. Whether you&apos;re optimizing for performance or building cross-database solutions, SQLAlchemy&#x2019;s features and flexibility ensure you&apos;re well-equipped for the task.</p><p>So, keep experimenting, refining your workflows, and finding new ways to streamline your database interactions. The journey of mastering SQLAlchemy is as rewarding as the pipelines it powers. Hey everybody! Keep learning!</p>]]></content:encoded></item><item><title><![CDATA[Creating a USMLE-style question-and-answer generator]]></title><description><![CDATA[<p>We are going to start a project to use current technology to vastly increase our knowledge retention. We will do this by teaching ourselves, not ChatGPT, how to score high on a USMLE exam. We will do this by first defining a prompt and agent that will output a single</p>]]></description><link>https://www.codinginmedicine.com/creating-a-usmle-style-question-generator/</link><guid isPermaLink="false">668d30e22564cc00011f8838</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Fri, 08 Nov 2024 23:00:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1606326608606-aa0b62935f2b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fHRlc3R8ZW58MHx8fHwxNzMwNjc0MjkzfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1606326608606-aa0b62935f2b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fHRlc3R8ZW58MHx8fHwxNzMwNjc0MjkzfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Creating a USMLE-style question-and-answer generator"><p>We are going to start a project to use current technology to vastly increase our knowledge retention. We will do this by teaching ourselves, not ChatGPT, how to score high on a USMLE exam. We will do this by first defining a prompt and agent that will output a single best answer mcq. Once we get that working, we can move on to things like RAG and think of ways to tweak output numbers and difficulty.</p><p>The United States Medical Licensing Examination (USMLE) is a three-step examination for medical licensure in the United States. It assesses a physician&apos;s ability to apply knowledge, concepts, and principles, and to demonstrate fundamental patient-centered skills, that are important in health and disease and constitute the basis of safe and effective patient care. The exam is sponsored by the Federation of State Medical Boards (FSMB) and the National Board of Medical Examiners (NBME).</p><h2 id="collect-the-research">Collect the Research</h2><p>Now let&apos;s gather all the information we can about the layout and structure of the questions, Perplexity, Phind, or ChatGpt works well for this step. </p><h4 id="multiple-choice-questions-mcqs">Multiple-Choice Questions (MCQs)</h4><p><strong>Components of MCQs:</strong></p><ol><li><strong>Stem</strong>: The clinical vignette or lead-in question that provides context.</li><li><strong>Lead-in</strong>: The direct question posed to the examinee.</li><li><strong>Options</strong>: A set of possible answers, typically five choices (A to E), where one is the best or most correct answer.</li></ol><p><strong>Distractors</strong>:</p><ul><li>Distractors are incorrect options provided in multiple-choice questions designed to mislead or challenge the examinee. They are plausible enough to be considered but incorrect.</li><li>Purpose: They test the depth of the examinee&#x2019;s knowledge and ability to discern the correct answer from similar but incorrect choices.</li></ul><p><strong>Difficulty Levels</strong>:</p><ul><li>USMLE questions range from basic to highly complex. The difficulty is determined by factors such as the integration of multiple concepts, the specificity of the clinical scenario, and the level of critical thinking required.</li><li>Questions can be categorized into three levels:</li><li><strong>Low Difficulty</strong>: Requires recall of basic facts and straightforward application of knowledge.</li><li><strong>Moderate Difficulty</strong>: Involves understanding and applying multiple concepts to a clinical scenario.</li><li><strong>High Difficulty</strong>: Requires synthesis of information, advanced clinical reasoning, and decision-making skills.</li></ul><p><strong>Measurement of Difficulty</strong>:</p><ul><li><strong>Item Response Theory (IRT)</strong>: This statistical method is used to calibrate question difficulty and discriminate between different levels of examinee ability.</li><li><strong>Parameters</strong>: Difficulty (b-parameter), discrimination (a-parameter), and guessing (c-parameter).</li><li><strong>Calibration</strong>: Based on examinee&apos;responses, the difficulty of each question is adjusted to ensure accurate measurement of ability.</li></ul><h3 id="example-deep-dive-on-question-difficulty">Example Deep Dive on Question Difficulty</h3><p><strong>Basic Question</strong>:</p><ul><li><strong>Stem</strong>: A 24-year-old female presents with a sore throat and fever. Physical examination reveals pharyngeal erythema and exudates.</li><li><strong>Lead-in</strong>: What is the most likely diagnosis?</li><li><strong>Options</strong>:</li><li>A) Streptococcal pharyngitis (correct)</li><li>B) Viral pharyngitis</li><li>C) Mononucleosis</li><li>D) Allergic rhinitis</li><li>E) GERD</li></ul><p><strong>Moderate Difficulty Question</strong>:</p><ul><li><strong>Stem</strong>: A 50-year-old male with a history of chronic obstructive pulmonary disease (COPD) presents with increased dyspnea and productive cough. His temperature is 38.3&#xB0;C, and he has coarse breath sounds with wheezing.</li><li><strong>Lead-in</strong>: What is the best initial treatment?</li><li><strong>Options</strong>:</li><li>A) Antibiotics (correct)</li><li>B) Inhaled corticosteroids</li><li>C) Beta-blockers</li><li>D) Diuretics</li><li>E) Antihistamines</li></ul><p><strong>High Difficulty Question</strong>:</p><ul><li><strong>Stem</strong>: A 68-year-old female with a history of diabetes and hypertension presents with sudden onset of right-sided weakness and difficulty speaking. She was last seen normal 3 hours ago. Her blood pressure is 180/100 mmHg, and CT scan shows no hemorrhage.</li><li><strong>Lead-in</strong>: What is the next best step in management?</li><li><strong>Options</strong>:</li><li>A) IV thrombolytics (correct)</li><li>B) Aspirin</li><li>C) Clopidogrel</li><li>D) Heparin</li><li>E) Blood pressure control</li></ul><p>All of this content took 4 minutes with prompting. I knew exactly what I was looking for and could verify most of the returned information. Ok now that we&apos;ve learned all have all that info we know that we need certain instructions in the output, namely the stem, lead-in options, but I also want to add some extra step. We also need the reasoning about why each answer is right or wrong and for the right answer we want a deeper more detailed reason about why this answer is right compared to others. &#xA0;These will help guide the structure that we need. Thinking about getting this output to conform to a json structure now will speed up frontend development at a later point. We will save the difficulty problem for another tutorial. </p><h2 id="prompt-engineering">Prompt Engineering </h2><p>First let me plug two exciting technologies, that I hope to get to in another consumer. Fabric and Dspy. Fabric has made me in and even bigger consumer of digital information as I&apos;ve use the prompts in pipelines to quickly summarize YouTube videos and research papers and even summarize medium articles. Dspy is an interesting project where the prompt is not needed, and it&apos;s abstracted away, but fine tunes that hidden prompt to get better output. I&apos;m underselling this a lot and I will have a tutorial soon about this as well. <br>Now for the purposes of being transparent I came across this <a href="https://medium.com/@eshtatla/5-essential-ai-chatgpt-prompts-every-medical-student-and-doctor-should-be-using-to-10x-their-de3f97d3802a">article</a> that had a decent starting prompt template for what I wanted to do.</p><pre><code>import os 
import os
from dotenv import load_dotenv
from guidance import models, gen


load_dotenv(
    &quot;.env&quot;,
    override=True,
)


def generate_usmle_prompt(subject):

    initial_prompt = f&quot;&quot;&quot;
    You are developing a question bank for medical exams focusing on the topic of {subject}. The subject may be broad , so the first thing to thing about is refining the question based on a specific refined subject, like a disease, medication, sign, symptom, marker, chemical process, etc, though noting that it should always come back to a disease process. When creating the answers make sure to create distractors that could be part of a differential diagnosis 

    Generate a high-quality Single Best Answer (SBA) question using the following framework:

    
    Create the question from the stem in parentheses below, while the stem is separated to guide you, the basis introductory part of the question should be the paragraph comprised of the stems
    
    (Stem:
    Patient details (gender/age)
    Presenting complaint (PC)
    Relevant clinical history (HPC)
    Physical examination findings
    Diagnostic test results (optional)
    
    Lead in Question stem: 
    )
    
    
    Answer options:
    [Insert plausible answer option]
    [Insert plausible answer option]
    [Insert plausible answer option]
    [Insert plausible answer option]
    [Insert plausible answer option]

    Explanation:
    For each answer option, provide a brief explanation of why it is correct or incorrect.
    
    Why this is the most appropriate answer:
    (this is an optional section to explain why the correct answer is the best choice in more detail)
    Given the clinical picture and the likely diagnosis of [insert condition], the most probable cause of the patient&apos;s symptoms is [insert correct answer option].&quot;&quot;&quot;

    lllm = models.LiteLLMCompletion(&quot;gpt-4o&quot;, echo=False)

    lllm += initial_prompt + gen(name=&quot;definition&quot;)

    question = lllm[&quot;definition&quot;]

    return question


def main():
    subject = input(&quot;Enter a medical subject: &quot;)
    print(&quot;Generating initial prompt...&quot;)
    initial_prompt = generate_usmle_prompt(subject)

    print(initial_prompt)


if __name__ == &quot;__main__&quot;:
    main()

</code></pre><p>If I run the program with the input &quot;serious congenital virus&quot; </p><pre><code>**Question:**

A 3-day-old male neonate presents with lethargy, poor feeding, and a fever of 38.5&#xB0;C. The mother reports that the baby was born at term via vaginal delivery without complications. The mother had no significant prenatal history and tested negative for Group B Streptococcus. On physical examination, the neonate is jaundiced, has hepatosplenomegaly, and exhibits a petechial rash. A complete blood count reveals thrombocytopenia and elevated liver enzymes. 

What is the most likely diagnosis?

A) Cytomegalovirus (CMV) infection
B) Group B Streptococcus (GBS) sepsis
C) Neonatal herpes simplex virus (HSV) infection
D) Toxoplasmosis
E) Rubella

**Explanation:**

A) Cytomegalovirus (CMV) infection
- **Incorrect:** While CMV can cause jaundice, hepatosplenomegaly, and thrombocytopenia, it is less likely to present with a petechial rash and fever in the neonatal period.

B) Group B Streptococcus (GBS) sepsis
- **Incorrect:** GBS sepsis can present with fever and lethargy, but it is less likely to cause jaundice, hepatosplenomegaly, and a petechial rash.

C) Neonatal herpes simplex virus (HSV) infection
- **Correct:** HSV infection in neonates can present with fever, lethargy, poor feeding, jaundice, hepatosplenomegaly, and a petechial rash. The presence of these symptoms along with the elevated liver enzymes and thrombocytopenia makes HSV the most likely diagnosis.

D) Toxoplasmosis
- **Incorrect:** Toxoplasmosis can cause jaundice and hepatosplenomegaly, but it typically presents with other findings such as chorioretinitis and intracranial calcifications, which are not mentioned in this case.

E) Rubella
- **Incorrect:** Congenital rubella syndrome can cause jaundice and hepatosplenomegaly, but it is more commonly associated with cataracts, congenital heart defects, and sensorineural deafness, which are not described in this case.

**Why this is the most appropriate answer:**
Given the clinical picture and the likely diagnosis of neonatal herpes simplex virus (HSV) infection, the most probable cause of the patient&apos;s symptoms is HSV infection. The combination of fever, lethargy, poor feeding, jaundice, hepatosplenomegaly, petechial rash, thrombocytopenia, and elevated liver enzymes strongly suggests HSV as the underlying cause.</code></pre><p>The output is decent, but not perfect yet. this is with the Gpt 4 model: what would be interesting is to see how other models compare to each other. We will test that in another session but now, I&apos;ll just rewrite the code a little to get strict json output. This wa I can properly save the output to a database, in case i want this particularly generated question to pop up again. Running the program again gives me this output:</p><pre><code>Enter a medical subject: diabetes
Generating initial prompt...
</code></pre><pre><code class="language-json">{
    &quot;question&quot;: &quot;A 45-year-old male presents to the clinic with excessive thirst and frequent urination. He reports a history of slowly progressive kidney failure. On physical examination, his blood pressure is 130/85 mmHg, and he appears well-hydrated. Laboratory tests reveal normal blood glucose levels, but a low urine osmolality. Which of the following is the most likely diagnosis?&quot;,
    &quot;choices&quot;: [
        {
            &quot;choice&quot;: &quot;Diabetes Mellitus Type 1&quot;,
            &quot;explanation&quot;: &quot;Diabetes Mellitus Type 1 is characterized by hyperglycemia due to autoimmune destruction of insulin-producing beta cells. This patient has normal blood glucose levels, making this diagnosis unlikely.&quot;
        },
        {
            &quot;choice&quot;: &quot;Diabetes Mellitus Type 2&quot;,
            &quot;explanation&quot;: &quot;Diabetes Mellitus Type 2 involves insulin resistance and is also characterized by hyperglycemia. The patient&apos;s normal blood glucose levels do not support this diagnosis.&quot;
        },
        {
            &quot;choice&quot;: &quot;Diabetes Insipidus&quot;,
            &quot;explanation&quot;: &quot;Diabetes Insipidus is characterized by excessive thirst and urination due to a deficiency of antidiuretic hormone (ADH) or renal insensitivity to ADH, leading to dilute urine. The patient&apos;s symptoms and low urine osmolality are consistent with this condition.&quot;,
            &quot;reasoning&quot;: &quot;Given the clinical picture and the likely diagnosis of Diabetes Insipidus, the most probable cause of the patient&apos;s symptoms is a deficiency or insensitivity to antidiuretic hormone, leading to the production of large volumes of dilute urine.&quot;,
            &quot;correct_answer&quot;: true
        },
        {
            &quot;choice&quot;: &quot;Chronic Kidney Disease&quot;,
            &quot;explanation&quot;: &quot;Chronic Kidney Disease can cause polyuria, but it is usually associated with other symptoms such as hypertension and electrolyte imbalances. The patient&apos;s normal blood pressure and low urine osmolality suggest a different diagnosis.&quot;
        },
        {
            &quot;choice&quot;: &quot;Primary Polydipsia&quot;,
            &quot;explanation&quot;: &quot;Primary Polydipsia involves excessive fluid intake leading to dilute urine. However, it is less likely in the context of slowly progressive kidney failure and the specific laboratory findings presented.&quot;
        }
    ]
}
</code></pre><p>This output has the structure I want, though I&apos;m not necessarily satisfied with the length of the clinical vignette for the questions, they should be longer with more details. We can explore expanding this by prompt engineering which we will tackle next time. </p><p>In this session, we embarked on an exciting journey to enhance our knowledge retention while preparing for the United States Medical Licensing Examination (USMLE). We began by dissecting the structure and components of multiple-choice questions (MCQs), which are crucial for the exam. We identified the essential elements of MCQs&#x2014;stems, lead-ins, options, and distractors&#x2014;along with the varying levels of difficulty that characterize USMLE questions. By using statistical methods such as Item Response Theory (IRT), we aim to calibrate question difficulty and improve our assessment strategies. Our initial efforts yielded a structured JSON output that aligns with our goal of having a MCQ database, &#xA0;though I&apos;m not necessarily satisfied with the length of the clinical vignette for the questions--they should be longer with more details. We can explore expanding this by prompt engineering which we will tackle next time. </p><p>Hey everyone, let&apos;s keep teaching and learning!</p>]]></content:encoded></item><item><title><![CDATA[Understanding Gists for Sharing Code]]></title><description><![CDATA[<h3 id="introduction">Introduction</h3><p>Sharing code snippets efficiently is crucial for collaboration and learning. GitHub Gists offer a streamlined way to share code or text snippets, making them accessible to anyone with a link. This article explores the concept of Gists, their advantages, and how to manage them effectively.</p><h4 id="what-are-gists">What are Gists?</h4><p>Gists</p>]]></description><link>https://www.codinginmedicine.com/understanding-gists-for-sharing-code/</link><guid isPermaLink="false">672691af0665240001b48448</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Wed, 06 Nov 2024 13:01:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1623591586852-cc0e7bcf98cf?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDY5fHxzY3JpcHR8ZW58MHx8fHwxNzMwNjM4NTY5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<h3 id="introduction">Introduction</h3><img src="https://images.unsplash.com/photo-1623591586852-cc0e7bcf98cf?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDY5fHxzY3JpcHR8ZW58MHx8fHwxNzMwNjM4NTY5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Understanding Gists for Sharing Code"><p>Sharing code snippets efficiently is crucial for collaboration and learning. GitHub Gists offer a streamlined way to share code or text snippets, making them accessible to anyone with a link. This article explores the concept of Gists, their advantages, and how to manage them effectively.</p><h4 id="what-are-gists">What are Gists?</h4><p>Gists are a feature of GitHub that allows users to share small pieces of code or text. They can be public, allowing anyone to view them, or private, restricting access to the creator and those with the link. Gists are ideal for sharing code examples, notes, or scripts quickly and easily.</p><h4 id="advantages-of-using-gists">Advantages of Using Gists</h4><ul><li><strong>Simplicity</strong>: Gists are easy to create and share, requiring only a GitHub account.</li><li><strong>Ease of Sharing</strong>: A simple URL makes Gists accessible to anyone with the link.</li><li><strong>Version Control</strong>: Like full GitHub repositories, Gists support version control, enabling users to track changes and revert to previous versions if needed.</li><li><strong>Comparison with Full Repositories</strong>: While full repositories are suitable for larger projects, Gists are perfect for smaller, standalone snippets.</li></ul><h4 id="creating-and-managing-gists-with-github-cli">Creating and Managing Gists with GitHub CLI</h4><p>The GitHub CLI (<code>gh</code>) provides a powerful way to manage Gists directly from the terminal. Here are some example commands:</p><p><strong>Creating a Gist</strong>:</p><pre><code class="language-bash">gh gist create my_script.sh --public --desc &quot;A simple bash script&quot;
</code></pre><p>This command creates a public Gist with the contents of <code>my_script.sh</code> and the specified description. For a private Gist, omit the <code>--public</code> flag.</p><p><strong>Editing a Gist</strong>:</p><pre><code class="language-bash">gh gist edit &lt;gist_id&gt; --add new_file.txt
</code></pre><p>This command adds a new file to an existing Gist.</p><p><strong>Deleting a Gist</strong>:</p><pre><code class="language-bash">gh gist delete &lt;gist_id&gt;
</code></pre><p>This command deletes the specified Gist.</p><p><strong>Cloning a Gist</strong>:</p><pre><code class="language-bash">git clone https://gist.github.com/&lt;gist_id&gt;.git
</code></pre><p>This command clones the Gist repository locally.</p><h4 id="advanced-gist-management-with-gistyc">Advanced Gist Management with Gistyc</h4><p>For more robust Gist management, the Gistyc library offers additional functionalities. Gistyc is a Python-based toolkit that allows users to create, update, and delete Gists from the command line or within a Python program. It can be integrated into CI/CD pipelines for automated Gist management.</p><p><strong>Creating a Gist with Gistyc</strong>:</p><pre><code class="language-python">from gistyc import GISTyc
gist_api = GISTyc(auth_token=&quot;YOUR_GITHUB_TOKEN&quot;)
response_data = gist_api.create_gist(file_name=&quot;my_script.py&quot;)
</code></pre><p><strong>Updating a Gist with Gistyc</strong>:</p><pre><code class="language-python">gist_api.update_gist(file_name=&quot;my_script.py&quot;, gist_id=&quot;GIST_ID&quot;)
</code></pre><p><strong>Deleting a Gist with Gistyc</strong>:</p><pre><code class="language-python">gist_api.delete_gist(gist_id=&quot;GIST_ID&quot;)
</code></pre><p><strong>Listing All Gists</strong>:</p><pre><code class="language-python">gist_list = gist_api.get_gists()
</code></pre><p>Gistyc provides a more programmatic approach to managing Gists. It supports operations like creating, updating, and deleting Gists using a GitHub personal access token. Additionally, Gistyc can handle multiple files and directories, making it ideal for managing large sets of Gists.</p><h4 id="use-cases-and-limitations">Use Cases and Limitations</h4><p>Gists are commonly used for sharing code snippets in tutorials, documentation, and collaborative projects. However, they have limitations, such as the inability to manage large projects or complex version histories. Users should consider these factors when choosing between Gists and full repositories.</p><h4 id="conclusion">Conclusion</h4><p>Gists provide a convenient and efficient way to share code snippets, with the added benefits of simplicity and version control. Whether you&apos;re collaborating with a team or sharing a quick code example, Gists are a valuable tool in any developer&apos;s toolkit. Explore Gists today to enhance your code-sharing capabilities.</p>]]></content:encoded></item><item><title><![CDATA[Setting up Airflow for ETL development]]></title><description><![CDATA[<p>This is part of a larger series of development and setup steps to build a self-contained Medical Record Database using ETL and other technologies. While a lot of what I do here can easily be scripted with pure Python, I am always exploring open-source ways to do things in a</p>]]></description><link>https://www.codinginmedicine.com/setting-up-airflow-for-etl-development/</link><guid isPermaLink="false">67263ce50665240001b4838a</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Sun, 03 Nov 2024 10:44:22 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1728115342521-1c1433ef0cc3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI4fHxwaXBlbGluZXxlbnwwfHx8fDE3MzA1ODYyMTZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1728115342521-1c1433ef0cc3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI4fHxwaXBlbGluZXxlbnwwfHx8fDE3MzA1ODYyMTZ8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Setting up Airflow for ETL development"><p>This is part of a larger series of development and setup steps to build a self-contained Medical Record Database using ETL and other technologies. While a lot of what I do here can easily be scripted with pure Python, I am always exploring open-source ways to do things in a structured manner. I hope you find the content useful.</p><h3 id="introduction-to-apache-airflow">Introduction to Apache Airflow</h3><p>Apache Airflow is a powerful platform used to programmatically author, schedule, and monitor workflows. It is particularly popular in the data engineering and data science communities for orchestrating complex data workflows, including data ingestion and transformation tasks, such as running dbt (data build tool) models. Airflow allows users to define workflows as code, making it easy to manage, version, and share workflows across teams.</p><h2 id="key-features-of-apache-airflow">Key Features of Apache Airflow</h2><h3 id="directed-acyclic-graphs-dags">Directed Acyclic Graphs (DAGs)</h3><p>At the core of Apache Airflow is the concept of Directed Acyclic Graphs (DAGs). A DAG is a collection of all the tasks you want to run, organized in a way that reflects their relationships and dependencies. Each node in the DAG represents a task, and the edges define the order in which tasks should be executed. DAGs ensure that tasks are executed in a specific sequence without any cycles, which means a task cannot depend on itself, either directly or indirectly.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.codinginmedicine.com/content/images/2024/11/image-3.png" class="kg-image" alt="Setting up Airflow for ETL development" loading="lazy" width="1172" height="85" srcset="https://www.codinginmedicine.com/content/images/size/w600/2024/11/image-3.png 600w, https://www.codinginmedicine.com/content/images/size/w1000/2024/11/image-3.png 1000w, https://www.codinginmedicine.com/content/images/2024/11/image-3.png 1172w" sizes="(min-width: 720px) 720px"><figcaption>Simple Pipeline example. Each Node(Task) can be a seperate script processing the previous nodes output</figcaption></figure><h3 id="integration-with-various-data-tools">Integration with Various Data Tools</h3><p>Apache Airflow is designed to be <em><strong>extensible</strong></em> and integrates seamlessly with a wide range of data tools and services. It supports various operators and hooks that allow you to interact with databases, cloud services, and other data processing tools. This makes it easy to create workflows that involve multiple systems, such as extracting data from a database, transforming it using a tool like dbt, and loading it into a data warehouse.</p><h3 id="web-interface-for-monitoring">Web Interface for Monitoring</h3><p>Airflow provides a rich web-based user interface that allows users to monitor and manage workflows. The UI provides a clear view of the DAGs, their status, and the logs of each task. Users can trigger tasks manually, view task dependencies, and even retry failed tasks directly from the interface. This makes it easy to keep track of complex workflows and quickly identify and resolve issues.</p><h4 id="setting-the-environment-with-docker-compose">Setting the Environment with Docker-compose</h4><p>Docker-Compose is particularly useful for setting up Apache Airflow in a development or testing environment, as it allows you to define all the necessary services in a single configuration file and start them with a single command. We will download the official download image, edit it, create a dockerfile, and add some plugins, with one simple bash script. </p><pre><code class="language-bash">#!/bin/bash

# Define custom ports
WEB_SERVER_PORT=8081
FLOWER_PORT=5556

# Create necessary directories
mkdir -p ./dags ./logs ./plugins

# Set environment variable for Airflow user
echo -e &quot;AIRFLOW_UID=$(id -u)&quot; &gt; .env

# Download the docker-compose.yaml file
curl -LfO &apos;https://airflow.apache.org/docs/apache-airflow/2.10.2/docker-compose.yaml&apos;

# Change permissions to make the file writable
chmod u+w docker-compose.yaml

# Modify the docker-compose.yaml file to use custom ports
sed -i &quot;s/8080:8080/${WEB_SERVER_PORT}:8080/g&quot; docker-compose.yaml
sed -i &quot;s/5555:5555/${FLOWER_PORT}:5555/g&quot; docker-compose.yaml

# Uncomment the build line and remove the image line
sed -i &apos;/^\s*image:.*apache\/airflow/d&apos; docker-compose.yaml
sed -i &apos;s/^\s*# build: \./  build: ./&apos; docker-compose.yaml

# Verify the modification
if grep -q &apos;^\s*build: \.$&apos; docker-compose.yaml; then
    echo &quot;Successfully updated docker-compose.yaml with build context.&quot;
    sleep 5
else
    echo &quot;Failed to update docker-compose.yaml with build context.&quot; &gt;&amp;2
    exit 1
fi
# Create a Dockerfile to install dbt and plugins
cat &lt;&lt;EOF &gt; Dockerfile
FROM apache/airflow:2.10.2

# Install dbt
RUN pip install dbt-core dbt-postgres

# Install Airflow plugins
RUN pip install apache-airflow-providers-slack
RUN pip install apache-airflow-providers-amazon
RUN pip install apache-airflow-providers-google
RUN pip install apache-airflow-providers-postgres

# Switch to the airflow user
USER airflow
EOF

# Build the custom Docker image
docker-compose build

# Initialize the Airflow database
docker-compose up airflow-init

# Start Airflow services in detached mode
docker-compose up -d

# Output the access information
echo &quot;Airflow is running on http://localhost:${WEB_SERVER_PORT}&quot;
echo &quot;Flower is running on http://localhost:${FLOWER_PORT}&quot;</code></pre><p>In essence, the script sets env variables and modifies the incoming docker-compose file, and executes. I have dbt installed along with some other airflow plugins orchestrated in the created Dockerfile, which you can modify to your preferences. I&apos;ll share this bash script with this <a href="https://gist.github.com/gyasis/0bde4e559ce1a82a4ed289f680834a19"><strong><em>gist</em></strong></a>, make sure if your environment is Linux, you &apos;chmod +x &lt;gist_file&gt;&apos; to make it executable. It goes without saying to have docker and docker-compose installed on your system. &#xA0;Quick point--you can set your port variables which can be needed if you are running a lot of docker-containers. &#xA0;I have many different containers, and I don&apos;t want the ports on my host machine conflicting with each other. </p><h3 id="a-quick-explanation-of-the-docker-compose-file">A quick explanation of the Docker-Compose file</h3><p>When setting up Apache Airflow using Docker-Compose, several services are typically included:</p><ul><li><strong>Scheduler</strong>: The scheduler is responsible for scheduling jobs and ensuring that tasks are executed according to their dependencies and schedules. It continuously monitors the DAGs and triggers tasks when their dependencies are met.</li><li><strong>Webserver</strong>: The webserver hosts the Airflow web interface, allowing users to interact with the DAGs, view logs, and manage tasks.</li><li><strong>Worker</strong>: Workers are responsible for executing the tasks defined in the DAGs. In a distributed setup, multiple workers can be used to parallelize task execution and improve performance.</li><li><strong>Init Service</strong>: The init service is used to initialize the Airflow database and ensure that all necessary configurations are in place before starting the other services.</li></ul><h4 id="running-services">Running Services</h4><p>Once you execute the script and there are no errors the echo statements have something like this: </p><figure class="kg-card kg-image-card"><img src="https://www.codinginmedicine.com/content/images/2024/11/image-1.png" class="kg-image" alt="Setting up Airflow for ETL development" loading="lazy" width="414" height="41"></figure><p>You can now navigate to localhost:8081 and view this: </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.codinginmedicine.com/content/images/2024/11/image-2.png" class="kg-image" alt="Setting up Airflow for ETL development" loading="lazy" width="1905" height="827" srcset="https://www.codinginmedicine.com/content/images/size/w600/2024/11/image-2.png 600w, https://www.codinginmedicine.com/content/images/size/w1000/2024/11/image-2.png 1000w, https://www.codinginmedicine.com/content/images/size/w1600/2024/11/image-2.png 1600w, https://www.codinginmedicine.com/content/images/2024/11/image-2.png 1905w" sizes="(min-width: 1200px) 1200px"><figcaption>Feel free to navigate the interface or bash into the container to verify the &apos;dbt --version&apos;</figcaption></figure><p>You will see a lot of example dags. </p><h4 id="recap">Recap</h4><p>In this tutorial, we explored how to set up Apache Airflow. By leveraging Airflow&apos;s powerful workflow orchestration capabilities, you can manage complex data processes more effectively and efficiently. We covered the essential features of Airflow, including Directed Acyclic Graphs (DAGs), integration with various data tools, and the intuitive web interface for monitoring workflows.</p><p>Additionally, we walked through the process of using Docker-Compose to simplify the environment setup, ensuring that all necessary services are configured and running seamlessly. With the provided bash script, you can easily customize your Airflow instance to fit your specific needs, including adding plugins and managing port configurations to prevent conflicts.</p><p>Now that you have a solid foundation for using Apache Airflow, you can begin to implement it in your own data projects. Whether you&apos;re automating data ingestion, transformation, or analysis, Airflow provides a structured and scalable solution that can grow with your needs. I hope this tutorial has equipped you with the knowledge and tools to harness the full potential of Apache Airflow in your workflows. </p><p>Hey everyone, let&apos;s keep teaching and learning!</p>]]></content:encoded></item><item><title><![CDATA["Creating and Managing Scalable Application Environments with Traefik and Docker: A Comprehensive Tutorial"]]></title><description><![CDATA[<p>Traefik is an open-source reverse proxy and load balancer that enables you to define your own route rules, SSL certificates, and more for your applications. It integrates perfectly with containerized environments such as Docker, Kubernetes, etc.</p><p>In this series, we are going to cover how to set up Traefik in</p>]]></description><link>https://www.codinginmedicine.com/creating-and-managing-scalable-application-environments-with-traefik-and-docker-a-comprehensive-tutorial/</link><guid isPermaLink="false">64854c5a26cae10001046c31</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Sun, 11 Jun 2023 10:00:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1639322537231-2f206e06af84?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDcwfHxuZXR3b3JrfGVufDB8fHx8MTY4NjQ1ODc3NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1639322537231-2f206e06af84?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDcwfHxuZXR3b3JrfGVufDB8fHx8MTY4NjQ1ODc3NXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="&quot;Creating and Managing Scalable Application Environments with Traefik and Docker: A Comprehensive Tutorial&quot;"><p>Traefik is an open-source reverse proxy and load balancer that enables you to define your own route rules, SSL certificates, and more for your applications. It integrates perfectly with containerized environments such as Docker, Kubernetes, etc.</p><p>In this series, we are going to cover how to set up Traefik in a Docker environment, how to route and balance traffic, and how to secure your applications.</p><h2 id="setting-up-the-environment"><strong>Setting Up the Environment</strong></h2><p>First, make sure that you have Docker and Docker Compose installed on your machine. If not, you can follow the official Docker documentation to install it.</p><h2 id="creating-a-traefik-configuration"><strong>Creating a Traefik Configuration</strong></h2><p>Let&apos;s begin by creating a configuration file for Traefik. We&apos;re going to use YAML for this:</p><p>Create a file named <code>traefik.yml</code> and add the following content:</p><pre><code>
entryPoints:
  web:
    address: &quot;:80&quot;
  websecure:
    address: &quot;:443&quot;

providers:
  docker:
    endpoint: &quot;unix:///var/run/docker.sock&quot;
    watch: true
    exposedByDefault: false
</code></pre><p>In this configuration, we have defined two entry points: web for HTTP (port 80) and websecure for HTTPS (port 443), comparable to the body&apos;s pain pathways. &#xA0;These pathways, much like their biological counterparts, serve unique purposes. The &quot;web&quot; pathway handles standard, non-secure communication, while the &quot;websecure&quot; pathway is designed for encrypted, secure communication. Their functionalities parallel how acute pain warns the body of immediate harm, and chronic pain indicates ongoing issues.</p><p>We introduce a Docker provider into this setup, which mirrors the role of the nervous system. This provider monitors changes in the Docker environment, regulating data flow and adapting as needed, akin to how the nervous system modulates and responds to body signals.</p><p>We can extend the analogy by comparing these networks to specific regions in the brain, each fulfilling a unique function. Much like the frontal lobe&apos;s role in decision making and the occipital lobe&apos;s in visual processing, each network caters to a particular type of web service or application.</p><p>To ensure precise communication&#x2014;similar to how nerve signals are directed to the right part of the brain&#x2014;we implement routing rules in Traefik. These rules guide incoming requests, much as the nervous system routes signals to the appropriate brain regions for processing.</p><p>The flexibility of this system is its main strength, allowing us to establish as many networks as necessary. This mirrors how the body manages different kinds of pain signals, directing them through various channels based on their unique characteristics. In doing so, we optimize our system&apos;s functionality and responsiveness, leading to an efficient environment for our applications.</p><h2 id="creating-the-docker-compose-file"><strong>Creating the Docker Compose File</strong></h2><p>Next, create a <code>docker-compose.yml</code> file in the same directory with the following content:</p><pre><code>version: &apos;3&apos;

services:
  traefik:
    image: traefik:v2.4
    command:
      - &quot;--api.insecure=true&quot;
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
      - &quot;8080:8080&quot;
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.yml:/etc/traefik/traefik.yml
    networks:
      - web

networks:
  web:
    external: true
</code></pre><p>Here, we define a service named <code>traefik</code> that uses the Traefik image from Docker Hub. We expose ports 80 (HTTP), 443 (HTTPS), and 8080 (Traefik&apos;s dashboard). We mount the Docker socket and our Traefik configuration file into the container.</p><h2 id="starting-traefik"><strong>Starting Traefik</strong></h2><p>You can start Traefik by running this command:</p><pre><code>docker-compose up -d</code></pre><p>This command will pull the necessary images and start the Traefik service in the background.</p><p>You should now be able to access Traefik&apos;s dashboard by going to <code>http://localhost:8080/dashboard</code>.</p><h2 id="creating-and-deploying-an-example-application"><strong>Creating and Deploying an Example Application</strong></h2><p>Now, let&apos;s create an example application and deploy it with Docker Compose.</p><p>Create a new <code>docker-compose.yml</code> file in a different directory with the following content:</p><pre><code>version: &apos;3&apos;

services:
  app:
    image: nginx
    labels:
      - &quot;traefik.enable=true&quot;
      - &quot;traefik.http.routers.app.rule=Host(`app.localhost`)&quot;
    networks:
      - web

networks:
  web:
    external: true
</code></pre><p>This configuration defines an application named <code>app</code> that uses the Nginx image from Docker Hub. &#xA0;The labels given to the service instruct Traefik to create a route rule for this application. It tells Traefik that the application can be accessed by going to <code>http://app.localhost</code>.</p><p>Note: In a real-world scenario, you would replace <code>localhost</code> with your domain name.</p><p>Now, let&apos;s run this application by using the following command:</p><pre><code>docker-compose up -d</code></pre><h2 id="testing-the-application"><strong>Testing the Application</strong></h2><p>If you have configured everything correctly, you should now be able to access your application by going to <code>http://app.localhost</code> in your web browser. Note that you may need to add a mapping in your hosts file if your operating system doesn&apos;t automatically resolve <code>*.localhost</code> addresses.</p><p>The Nginx start page should be displayed.</p><h2 id="inspecting-the-traefik-dashboard"><strong>Inspecting the Traefik Dashboard</strong></h2><p>If you go back to the Traefik dashboard (<code>http://localhost:8080/dashboard</code>), you should see your <code>app</code> service listed there. You can inspect the route rules and other configuration details.</p><p>This was a basic tutorial to set up Traefik in a Docker environment and deploy a simple application.</p><p>In further parts of this series, we will discuss more advanced topics such as:</p><ul><li>Load balancing between multiple instances of an application</li><li>Adding SSL certificates with Let&apos;s Encrypt</li><li>Redirecting HTTP traffic to HTTPS</li><li>Routing based on path or headers</li></ul><h2 id="conclusion"><strong>Conclusion</strong></h2><p>By using Traefik with Docker, we can create flexible and scalable environments for our applications. Traefik&apos;s integration with Docker makes it easy to define route rules, load balance traffic, and add SSL, giving us full control over the networking of our containerized applications.</p>]]></content:encoded></item><item><title><![CDATA[Harnessing the Power of C++: Journey into New Territory]]></title><description><![CDATA[<p>Akin to the diverse specialties in medicine, the programming world is vast, each language offering unique perspectives and tools to solve problems. Despite having a strong grasp on Python, Rust, Node.js, and R, I often found myself seeking something more, akin to a physician needing a specialized diagnostic tool</p>]]></description><link>https://www.codinginmedicine.com/harnessing-the-power-of-c/</link><guid isPermaLink="false">64703cf81defde000100bcc1</guid><category><![CDATA[C++]]></category><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Mon, 29 May 2023 15:39:19 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1487491491904-a48f73cd4078?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDMyfHxCdXN0ZXIlMjBzd29yZHxlbnwwfHx8fDE2ODUwNzcyOTF8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1487491491904-a48f73cd4078?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDMyfHxCdXN0ZXIlMjBzd29yZHxlbnwwfHx8fDE2ODUwNzcyOTF8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Harnessing the Power of C++: Journey into New Territory"><p>Akin to the diverse specialties in medicine, the programming world is vast, each language offering unique perspectives and tools to solve problems. Despite having a strong grasp on Python, Rust, Node.js, and R, I often found myself seeking something more, akin to a physician needing a specialized diagnostic tool to identify and treat a unique disease. I needed a language that could offer me raw power, control, and a direct interface with system architecture. After careful introspection, I realized that my next foray into the programming landscape would be C++.</p><p>C++ - the language I had admired from afar - was now in the spotlight of my programming journey. Although my knowledge of Python, Rust, Node.js, and R served me well, I found myself constantly needing a plugin that could do something specific for a program I hadn&apos;t yet created. I yearned for the capability to extend functionality, to mold and shape software in ways that went beyond the boundaries of my existing skill set.</p><p>Just like a physician encountering a patient presenting unique symptoms might think of a rare but specific medical condition, such as Barth syndrome, I started to recognize that my programming needs were pointing me towards C++. The unique attributes of the language - raw power and control, the ability to manage resources and memory, and direct system level access - were all clear indications that C++ could be the panacea for my plugin development needs.</p><p>Moreover, my personal interest in computer vision projects drew me closer to C++. Libraries such as OpenCV have native support in C++, making it a go-to language for real-time computer vision, which relies heavily on speed and efficiency. Not only does C++ offer a wide range of libraries for various applications, but it also provides the high performance needed for computationally intensive tasks. It felt like the missing piece of the puzzle, the highly specialized tool that would augment my programming arsenal.</p><p>Now, let&apos;s dive deeper into the world of C++ and understand its advantages, how to set up a C++ environment on Linux using Conda, and how to write plugins and create our first &apos;Hello, World!&apos; program in C++.</p><h2 id="advantages-of-c">Advantages of C++</h2><p>If the world of programming languages was a hospital, C++ would be the highly respected and versatile surgeon, known for its performance, flexibility, and efficiency.</p><p>Like a medical professional needing to understand human anatomy in depth, mastering C++ requires an intimate knowledge of the underlying system architecture. However, this level of understanding pays off in the form of more robust and efficient programs.</p><h3 id="high-performance-and-efficiency">High Performance and Efficiency</h3><p>Much like a rare but specific medical condition, Barth syndrome, which presents with cardiolipin deficiency, neutropenia, and muscle weakness, C++ has unique attributes that set it apart from other languages. In C++, the idiosyncratic signs of raw power and control, ability to manage resources and memory, and direct system level access are all clear indications of the language&apos;s high performance and efficiency.</p><h3 id="flexibility-and-versatility">Flexibility and Versatility</h3><p>C++ is a multi-paradigm language. This means that it supports different styles of programming including procedural, object-oriented, and generic, offering programmers a wide array of tools to solve problems. It&apos;s like a diagnostician capable of recognizing and treating a wide variety of diseases.</p><h2 id="writing-plugins-with-c">Writing Plugins with C++</h2><p>Just as medical researchers often develop therapies to tackle specific diseases, C++ programmers can develop plugins to extend the functionality of existing software.</p><p>Plugins are dynamic libraries loaded by an application at runtime. Writing them in C++ can be particularly useful due to the language&apos;s efficiency and control. This is similar to administering targeted therapies in medical treatment, which work by targeting specific genes or proteins involved in the growth and survival of cancer cells, resulting in improved treatment outcomes.</p><h2 id="requirements-for-a-linux-conda-environment">Requirements for a Linux, Conda Environment</h2><p>A Conda environment can be thought of as a private room in a hospital. It isolates a specific space for each patient (or software project in our case) to avoid cross-contamination (interference between different software versions or dependencies).</p><p>To set up a C++ environment on Linux using Conda, you&apos;ll need the following:</p><ol><li>A Linux operating system. We&apos;ll assume a Ubuntu-based distribution for this guide.</li><li>Anaconda or Miniconda installed on your system. You can download it from their <a href="https://www.anaconda.com/">official website</a>.</li><li>Basic familiarity with the terminal commands.</li></ol><p>Once these prerequisites are in place, setting up the C++ environment is as simple as creating a new Conda environment, and installing the necessary C++ libraries.</p><h2 id="writing-compiling-and-running-a-c-program">Writing, Compiling, and Running a C++ Program</h2><p>Let&apos;s write a simple &apos;Hello, World!&apos; program in C++. This quintessential program is an excellent way to test our development environment.</p><p>First, we&apos;ll create the program. Open a text editor, type the following code, and then save the file as <code>hello_world.cpp</code>:</p><pre><code>#include&lt;iostream&gt;

int main() {
    std::cout &lt;&lt; &quot;Hello, World!&quot; &lt;&lt; std::endl;
    return 0;
}
</code></pre><p>In this program, <code>#include &lt;iostream&gt;</code> includes the input-output stream header file (<code>iostream</code>) into our program. The <code>main</code> function is the entry point of our program. <code>std::cout</code> prints the string &quot;Hello, World!&quot; to the console.</p><p>Once we have written the program, we&apos;ll need to compile it. In the terminal, navigate to the directory containing <code>hello_world.cpp</code>. Compile the C++ file using the <code>g++</code> compiler:</p><pre><code>g++ hello_world.cpp -o hello_world
</code></pre><p>The <code>-o</code> option lets us specify the output file name. In this case, the compiled program will be named <code>hello_world</code>.Upon successful compilation, a new executable file named <code>hello_world</code> will be created in the same directory.</p><p>Next, we&apos;ll run the program. In the terminal, type the following command:</p><pre><code>./hello_world
</code></pre><p>This command will execute the <code>hello_world</code> program, which will print &quot;Hello, World!&quot; to the console.</p><p>That&apos;s it! We&apos;ve written, compiled, and run our first C++ program.</p><p>Remember, you need the <code>g++</code> compiler installed on your system to compile C++ code. If you&apos;re using the Linux Conda environment setup we discussed earlier, the <code>g++</code> compiler should already be available. If not, you can install it with the package manager of your Linux distribution. For instance, on Ubuntu, use the command <code>sudo apt install g++</code>.</p><p>This basic &apos;Hello, World!&apos; program is just the beginning. With the power and flexibility of C++, the possibilities for creating complex applications, plugins, and more are virtually endless. &#xA0;It&apos;s an investment that provides the opportunity to create more efficient, powerful, and flexible solutions. I&apos;m eager to harness the full potential of this robust language, utilizing its native libraries for my computer vision projects and beyond. Stay tuned for more about this powerful, albeit difficult(in my opinion) language. Happy Coding!</p>]]></content:encoded></item><item><title><![CDATA[Mastering Classes in Python with a Medical Twist: A Comprehensive Tutorial]]></title><description><![CDATA[Using the context of medical applications we explore the implementation of Python classes.]]></description><link>https://www.codinginmedicine.com/master-python-classes-with-real-world-medical-examples/</link><guid isPermaLink="false">6462cec5bf352f0001dbb68c</guid><category><![CDATA[python]]></category><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Tue, 16 May 2023 01:04:18 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1629470937845-f3ea7502d14c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fHB5dGhvbiUyMGNsYXNzfGVufDB8fHx8MTY4NDE5ODYwOXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<h3 id="introduction">Introduction: </h3><img src="https://images.unsplash.com/photo-1629470937845-f3ea7502d14c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fHB5dGhvbiUyMGNsYXNzfGVufDB8fHx8MTY4NDE5ODYwOXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Mastering Classes in Python with a Medical Twist: A Comprehensive Tutorial"><p>Python, with its simplicity and readability, is a versatile programming language that has found its way into diverse fields, including medical science. One of its key features is the ability to create classes, encapsulating data and functions into an organized and reusable unit. This tutorial delves into Python classes, their syntax, attributes, the essential concept of &quot;self&quot;, and how they can be applied in medical scenarios, particularly pharmacology and pathology.</p><h3 id="understanding-the-basics-of-classes">Understanding the Basics of Classes: </h3><p>Classes, in Python, are blueprints for creating objects (instances), each equipped with a predefined set of attributes and methods. They form the backbone of object-oriented programming in Python, providing a structure to package data and functions together.</p><p>Consider a class as a template for a real-world entity. For instance, if we are creating a pharmacology application, a &apos;Drug&apos; class could represent the real-world concept of a drug. This class would have attributes (characteristics of the drug) and methods (actions that can be performed with the drug).</p><h3 id="defining-a-class">Defining a Class: </h3><p>To define a class in Python, we use the &apos;class&apos; keyword followed by the class name. Here&apos;s an example, creating a &apos;Drug&apos; class:</p><pre><code>class Drug:
    pass
</code></pre><p>This class currently does nothing, but we have laid the foundation for our &apos;Drug&apos; class.</p><h4 id="adding-attributes">Adding Attributes:</h4><p>Attributes represent the properties or characteristics associated with a class. They store essential data and represent the state of an object. For our &apos;Drug&apos; class, we can add attributes like &apos;name&apos;, &apos;dosage&apos;, and &apos;side_effects&apos;:</p><pre><code>class Drug:
    def __init__(self, name, dosage, side_effects):
        self.name = name
        self.dosage = dosage
        self.side_effects = side_effects
</code></pre><p>The init method, a constructor, is executed when an object is created from the class. Inside this method, we initialize the attributes using the &apos;self&apos; keyword.</p><h4 id="understanding-self">Understanding &quot;self&quot;:</h4><p>The &apos;self&apos; keyword in Python is a convention that references the instance of the class. It allows access to the attributes and methods within the class. When defining a method inside a class, &apos;self&apos; must be included as the first parameter, even though it&apos;s not explicitly passed when calling the method.</p><p>Let&apos;s explain with our &apos;Drug&apos; class. When we create a Drug object (let&apos;s say Paracetamol), &apos;self&apos; refers to this object, enabling us to set and access its attributes.</p><h4 id="accessing-attributes">Accessing Attributes:</h4><p>Having defined the attributes in our &apos;Drug&apos; class, we can access them using dot notation. Here&apos;s how we create an instance of the &apos;Drug&apos; class and print the attribute values:</p><pre><code>paracetamol = Drug(&quot;Paracetamol&quot;, &quot;500mg&quot;, [&quot;Nausea&quot;, &quot;Rashes&quot;])
print(paracetamol.name)  # Output: Paracetamol
print(paracetamol.dosage)  # Output: 500mg
print(paracetamol.side_effects)  # Output: [&apos;Nausea&apos;, &apos;Rashes&apos;]
</code></pre><p>Here, &apos;paracetamol&apos; is an instance (object) of the &apos;Drug&apos; class, and we access its attributes using dot notation.</p><h4 id="adding-methods">Adding Methods:</h4><p>Methods define the behavior of the objects created from the class. They are essentially functions defined within a class. For our &apos;Drug&apos; class, we can add a method &apos;display_info&apos; that prints the drug&apos;s information:</p><pre><code>class Drug:

    def __init__(self, name, dosage, side_effects):
        self.name = name
        self.dosage = dosage
        self.side_effects = side_effects
        

    def display_info(self):
        print(f&quot;Drug Name: {self.name}&quot;)
        print(f&quot;Dosage: {self.dosage}&quot;)
        print(f&quot;Side Effects: {self.side_effects}&quot;)

</code></pre><p>Notice that we have used &apos;self&apos; in our method definition to access the attributes. Now, we can call this method on an instance of the &apos;Drug&apos; class:</p><pre><code>paracetamol = Drug(&quot;Paracetamol&quot;, &quot;500mg&quot;, [&quot;Nausea&quot;, &quot;Rashes&quot;])
paracetamol.display_info()
</code></pre><p>This will output:</p><pre><code>Drug Name: Paracetamol
Dosage: 500mg
Side Effects: [&apos;Nausea&apos;, &apos;Rashes&apos;]
</code></pre><h3 id="inheritance-and-superclasses">Inheritance and Superclasses:</h3><p>Inheritance is a fundamental concept in object-oriented programming that allows one class (subclass) to inherit attributes and methods from another class (superclass). This promotes code reusability and a logical structure.</p><p>Consider a situation where we have a specific drug, such as an antibiotic. This &apos;Antibiotic&apos; class could inherit from the &apos;Drug&apos; class:</p><pre><code>class Antibiotic(Drug):
    def __init__(self, name, dosage, side_effects, antibiotic_class):
        super().__init__(name, dosage, side_effects)
        self.antibiotic_class = antibiotic_class
</code></pre><p>The &apos;super()&apos; function calls the constructor of the superclass, allowing us to access its methods and attributes. In this case, we use it to initialize the &apos;name&apos;, &apos;dosage&apos;, and &apos;side_effects&apos; attributes from the &apos;Drug&apos; class. We also add an extra attribute, &apos;antibiotic_class&apos;.</p><pre><code>amoxicillin = Antibiotic(&quot;Amoxicillin&quot;, &quot;500mg&quot;, [&quot;Nausea&quot;, &quot;Rashes&quot;], &quot;Penicillin&quot;)
amoxicillin.display_info()
print(f&quot;Antibiotic Class: {amoxicillin.antibiotic_class}&quot;)  # Output: Penicillin
</code></pre><p>In this example, &apos;amoxicillin&apos; is an instance of the &apos;Antibiotic&apos; class, which is a subclass of the &apos;Drug&apos; class. It inherits the attributes and methods of the &apos;Drug&apos; class and adds one more attribute specific to antibiotics.</p><h3 id="disease-process-a-practical-example">Disease Process: A Practical Example</h3><p>Python classes can be used effectively to model complex real-world processes, such as the progression of diseases. Let&apos;s delve into a comprehensive example of a disease process: the progression of diabetes.</p><p>In this case, we will define a &apos;Patient&apos; class, a &apos;Disease&apos; class, and a &apos;Diabetes&apos; subclass. A patient will have attributes such as &apos;name&apos;, &apos;age&apos;, &apos;weight&apos;, and &apos;blood_sugar_level&apos;, and the disease class will have &apos;name&apos;, &apos;symptoms&apos;, and &apos;treatment&apos;. Diabetes, as a subclass of Disease, will additionally have &apos;type&apos; (Type 1 or Type 2) as an attribute.</p><p><strong>Defining the Patient Class:</strong></p><pre><code>class Patient:
    def __init__(self, name, age, weight, blood_sugar_level):
        self.name = name
        self.age = age
        self.weight = weight
        self.blood_sugar_level = blood_sugar_level
</code></pre><p><strong>Defining the Disease Class:</strong></p><pre><code>class Disease:
    def __init__(self, name, symptoms, treatment):
        self.name = name
        self.symptoms = symptoms
        self.treatment = treatment
</code></pre><p><strong>Defining the Diabetes Subclass:</strong></p><pre><code>class Diabetes(Disease):
    def __init__(self, name, symptoms, treatment, type):
        super().__init__(name, symptoms, treatment)
        self.type = type
</code></pre><p>In this model, each &apos;Patient&apos; object could have a &apos;Disease&apos; object as an attribute, representing the disease the patient is suffering from.</p><pre><code>class Patient:
    def __init__(self, name, age, weight, blood_sugar_level, disease=None):
        self.name = name
        self.age = age
        self.weight = weight
        self.blood_sugar_level = blood_sugar_level
        self.disease = disease
</code></pre><p>In this case, &apos;disease&apos; is an optional attribute. If a patient is diagnosed with diabetes, this attribute can be updated to an instance of the &apos;Diabetes&apos; class.</p><p>Now, we can create a patient diagnosed with Type 2 Diabetes:</p><pre><code>diabetes_type2 = Diabetes(&quot;Diabetes&quot;, [&quot;Increased thirst&quot;, &quot;Frequent urination&quot;], &quot;Insulin Therapy&quot;, &quot;Type 2&quot;)
patient_john = Patient(&quot;John Doe&quot;, 50, 90, 180, diabetes_type2)
</code></pre><p>This example shows how Python classes can be used to model intricate real-world processes effectively, enhancing understanding and promoting better data organization.</p><h3 id="medical-assessment-and-treatment-a-class-based-approach">Medical Assessment and Treatment: A Class-Based Approach</h3><p>The process of assessing and treating a disease often follows a medical algorithm or decision tree, guiding healthcare professionals in their clinical decision-making. In western medicine, this approach often includes assessment, diagnosis, treatment, and follow-up.</p><p>We can create Python classes to model this process. Let&apos;s create a class &apos;MedicalAlgorithm&apos; that encompasses these steps. To demonstrate, we&apos;ll continue using diabetes as our example disease.</p><p><strong>Defining the MedicalAlgorithm Class:</strong></p><pre><code>class MedicalAlgorithm:
    def __init__(self, patient, disease):
        self.patient = patient
        self.disease = disease

    def assess(self):
        print(f&quot;Assessing {self.patient.name}&apos;s condition...&quot;)
        print(f&quot;Blood Sugar Level: {self.patient.blood_sugar_level}&quot;)
        print(f&quot;Symptoms: {self.disease.symptoms}&quot;)

    def diagnose(self):
        if self.patient.blood_sugar_level &gt; 125 and &quot;Increased thirst&quot; in self.disease.symptoms:
            print(f&quot;Diagnosis: {self.disease.name} - {self.disease.type}&quot;)
        else:
            print(&quot;Further tests required for definitive diagnosis.&quot;)

    def treat(self):
        print(f&quot;Initiating treatment for {self.patient.name}...&quot;)
        print(f&quot;Prescribed Treatment: {self.disease.treatment}&quot;)

    def follow_up(self):
        print(f&quot;Scheduled follow-up for {self.patient.name} in 4 weeks.&quot;)
</code></pre><p>This class takes a &apos;Patient&apos; object and a &apos;Disease&apos; object as input. It has four methods:</p><p>1.	assess(): This method prints the patient&apos;s symptoms and current blood sugar level.</p><p>2.	diagnose(): This method uses a simple algorithm to diagnose the disease based on the patient&apos;s blood sugar level and symptoms. If the blood sugar level is above a certain threshold and the patient exhibits particular symptoms, a diagnosis is made.</p><p>3.	treat(): This method initiates treatment for the patient based on the &apos;Disease&apos; object.</p><p>4.	follow_up(): This method schedules a follow-up appointment for the patient.</p><p>Now, we can apply this medical algorithm to our patient diagnosed with Type 2 Diabetes:</p><pre><code>medical_algorithm = MedicalAlgorithm(patient_john, diabetes_type2)
medical_algorithm.assess()
medical_algorithm.diagnose()
medical_algorithm.treat()
medical_algorithm.follow_up()
</code></pre><p>This will output:</p><pre><code>Assessing John Doe&apos;s condition...
Blood Sugar Level: 180
Symptoms: [&apos;Increased thirst&apos;, &apos;Frequent urination&apos;]
Diagnosis: Diabetes - Type 2
Initiating treatment for John Doe...
Prescribed Treatment: Insulin Therapy
Scheduled follow-up for John Doe in 4 weeks.
</code></pre><p>With this approach, we can effectively encapsulate the steps of a medical algorithm into a Python class. This example provides a simplified illustration; in reality, medical algorithms can be more complex and nuanced. However, this demonstration shows how Python classes can be used to model and organize such processes effectively.</p><h3 id="conclusion">Conclusion:</h3><p>Python classes, with their encapsulation of data and functions, play a vital role in structuring code for better organization and reusability. They&apos;re integral to object-oriented programming in Python, enabling you to define custom data types that match real-world entities.</p><p>The concept of &apos;self&apos; is crucial in defining and working with classes, as it provides access to an instance&apos;s attributes and methods within the class. By integrating the use of classes in a medical context, we&apos;ve shown how Python can be applied in diverse fields.</p><p>Keep practicing and experimenting with Python classes to solidify your understanding and explore their full potential. Mastering classes is a significant step towards becoming proficient in Python, opening the doors to more complex and powerful programming. Happy coding!</p>]]></content:encoded></item><item><title><![CDATA[Stash Your Way to a Better Git Workflow]]></title><description><![CDATA[<!--kg-card-begin: html--><p>Git stash is a command in Git that allows you to temporarily save changes that you&apos;ve made to your working directory without committing them. Stashing is useful when you need to switch to another branch or work on something else temporarily but want to come back to the</p>]]></description><link>https://www.codinginmedicine.com/git-stash-tutorial-comprehensive-guide-with-all-commands/</link><guid isPermaLink="false">6404d421897be700011d1c28</guid><category><![CDATA[git]]></category><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Sun, 05 Mar 2023 17:57:50 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1636031068622-98c9c161c613?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDM1fHxkZXNrJTIwZHJhd2VyfGVufDB8fHx8MTY3ODAzODcyOQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html--><img src="https://images.unsplash.com/photo-1636031068622-98c9c161c613?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDM1fHxkZXNrJTIwZHJhd2VyfGVufDB8fHx8MTY3ODAzODcyOQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Stash Your Way to a Better Git Workflow"><p>Git stash is a command in Git that allows you to temporarily save changes that you&apos;ve made to your working directory without committing them. Stashing is useful when you need to switch to another branch or work on something else temporarily but want to come back to the changes you were working on later.</p>

<p>Here are the main git stash commands you need to know:</p>

<ol>
<li><code>git stash save &quot;message&quot;</code>:</li>

   <p>This command saves your changes to the stash. You can add a message to describe the changes you&apos;re saving. The syntax is:</p>

   <pre><code>git stash save &quot;message&quot;
   </code></pre>

<li><code>git stash list</code>:</li>

   <p>This command lists all the stashes that you&apos;ve saved. The syntax is:</p>

   <pre><code>git stash list
   </code></pre>

<li><code>git stash apply</code>:</li>

   <p>This command applies the most recent stash to your working directory. The syntax is:</p>

   <pre><code>git stash apply
   </code></pre>

   <p>If you want to apply a specific stash, you can use the syntax:</p>

   <pre><code>git stash apply stash@{n}
   </code></pre>

   <p>where <code>n</code> is the index number of the stash you want to apply.</p>

<li><code>git stash pop</code>:</li>

   <p>This command applies the most recent stash to your working directory and removes it from the stash list. Essentially, it&apos;s like applying a stash with git stash apply and then immediately removing it with git stash drop. This can be useful when you&apos;re confident that you no longer need the saved changes in the stash, or if you want to apply a stash and clean up your stash list in one step. However, it&apos;s important to use git stash pop with caution, as once you pop a stash it cannot be easily  The syntax is:</p>

   <pre><code>git stash pop
   </code></pre>

   <p>If you want to pop a specific stash, you can use the syntax:</p>

   <pre><code>git stash pop stash@{n}
   </code></pre>

<li><code>git stash drop</code>:</li>

   <p>This command removes a specific stash from the stash list. The syntax is:</p>

   <pre><code>git stash drop stash@{n}
   </code></pre>

   <p>If you don&apos;t specify a stash, it will remove the most recent stash.</p>

<li><code>git stash clear</code>:</li>

   <p>This command removes all stashes from the stash list. The syntax is:</p>

   <pre><code>git stash clear
   </code></pre>

<li><code>git stash branch</code>:</li>

   <p>This command creates a new branch and applies the most recent stash to it. The syntax is:</p>

   <pre><code>git stash branch branchname
   </code></pre>

   <p>where <code>branchname</code> is the name of the new branch.</p>

</ol>

<!--kg-card-end: html--><p>In summary, Git stash is a powerful tool that can help you save changes temporarily and improve your workflow when working with Git. Whether you need to switch to another branch, work on something else temporarily, or simply clean up your commit history, Git stash has you covered. By mastering the commands outlined in this tutorial, you&apos;ll be able to use Git stash with confidence and take your Git skills to the next level. If you have any questions or feedback, feel free to leave a comment below!</p><!--kg-card-begin: html--><table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>git stash save &quot;message&quot;</code></td>
      <td>Saves changes to the stash with a message</td>
    </tr>
    <tr>
      <td><code>git stash list</code></td>
      <td>Lists all stashes</td>
    </tr>
    <tr>
      <td><code>git stash apply</code></td>
      <td>Applies the most recent stash</td>
    </tr>
    <tr>
      <td><code>git stash apply stash@{n}</code></td>
      <td>Applies the stash at index <code>n</code></td>
    </tr>
    <tr>
      <td><code>git stash pop</code></td>
      <td>Applies and removes the most recent stash</td>
    </tr>
    <tr>
      <td><code>git stash pop stash@{n}</code></td>
      <td>Applies and removes the stash at index <code>n</code></td>
    </tr>
    <tr>
      <td><code>git stash drop stash@{n}</code></td>
      <td>Removes the stash at index <code>n</code></td>
    </tr>
    <tr>
      <td><code>git stash drop</code></td>
      <td>Removes the most recent stash</td>
    </tr>
    <tr>
      <td><code>git stash clear</code></td>
      <td>Removes all stashes</td>
    </tr>
    <tr>
      <td><code>git stash branch branchname</code></td>
      <td>Creates a new branch with the most recent stash applied</td>
    </tr>
  </tbody>
</table>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[The Art of Docker Cleanup: How to Feng Shui Your Environment and Keep Your Containers Running Smoothly]]></title><description><![CDATA[<p>If you&apos;re constantly creating and destroying Docker environments, like me, &#xA0;you may find that your host machine&apos;s disk space fills up quickly. This can lead to unexpected errors, lost files, and reduced performance. Managing Docker environments can be a challenging task, especially when it comes</p>]]></description><link>https://www.codinginmedicine.com/the-art-of-docker-cleanup-how-to-feng-shui-your-environment-and-keep-your-containers-running-smoothly/</link><guid isPermaLink="false">63ef91a8ce20ea0001cdcf5f</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Sat, 18 Feb 2023 10:11:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1493953659556-556b14bdaca8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIyfHxjbGVhbnxlbnwwfHx8fDE2NzY2NDQ4Mzg&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1493953659556-556b14bdaca8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIyfHxjbGVhbnxlbnwwfHx8fDE2NzY2NDQ4Mzg&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="The Art of Docker Cleanup: How to Feng Shui Your Environment and Keep Your Containers Running Smoothly"><p>If you&apos;re constantly creating and destroying Docker environments, like me, &#xA0;you may find that your host machine&apos;s disk space fills up quickly. This can lead to unexpected errors, lost files, and reduced performance. Managing Docker environments can be a challenging task, especially when it comes to keeping your system clean and organized. This tutorial will cover some tips and best practices for reclaiming disk space in your Docker environment, including removing unused containers, images, networks, and volumes. By following these techniques, you can keep your system running smoothly and avoid running out of disk space.</p><p>Docker provides a number of tools for managing disk space, including removing unused objects, running the garbage collector, and using filters to limit the objects that will be removed. But lets get the basics out of the way first:</p><h2 id="docker-objects">Docker Objects</h2><p>There are three types of objects in Docker: images, containers, and volumes.</p><ul><li><strong>Images:</strong> An image is a read-only template that contains the application code, libraries, and dependencies required to run the application.</li><li><strong>Containers:</strong> A container is a running instance of an image. When a container is created, it is based on an image and contains all the necessary files and libraries to run the application.</li><li><strong>Volumes:</strong> A volume is a persistent data storage mechanism that can be shared between containers. Volumes are used to store data that needs to persist even when the container is removed.</li></ul><h2 id="removing-unused-objects">Removing Unused Objects</h2><p>To remove unused objects in Docker, you can use the <code>docker system prune</code> command. This command removes all unused containers, images, networks, and volumes from your system.</p><pre><code>docker system prune</code></pre><p>This command will ask for confirmation before removing the objects. If you want to remove all unused objects without confirmation, you can use the <code>--force</code> or <code>-f</code> option:</p><pre><code>$ docker system prune --force
</code></pre><h6 id="docker-prune-commands">Docker Prune Commands:</h6><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Function</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>docker system prune</td>
<td>Remove unused containers, images, networks, and volumes</td>
</tr>
<tr>
<td>docker system prune -a</td>
<td>Remove all unused objects, including containers, images, networks, and volumes</td>
</tr>
<tr>
<td>docker system prune -f</td>
<td>Force removal of all unused objects, without confirmation</td>
</tr>
<tr>
<td>docker system prune --volumes</td>
<td>Remove unused volumes</td>
</tr>
<tr>
<td>docker system prune --filter &quot;label=<label>&quot;</label></td>
<td>Remove objects matching a specific label</td>
</tr>
<tr>
<td>docker system prune --filter &quot;until=<duration>&quot;</duration></td>
<td>Remove objects that have not been used in a certain duration</td>
</tr>
<tr>
<td>docker system prune --filter &quot;dangling=true&quot;</td>
<td>Remove objects that are not associated with any container</td>
</tr>
<tr>
<td>docker system prune --filter &quot;networks=<network-id>&quot;</network-id></td>
<td>Remove unused networks</td>
</tr>
<tr>
<td>docker container prune</td>
<td>Remove all stopped containers</td>
</tr>
<tr>
<td>docker container prune --filter &quot;until=<duration>&quot;</duration></td>
<td>Remove containers that have not been used in a certain duration</td>
</tr>
<tr>
<td>docker image prune</td>
<td>Remove all unused images</td>
</tr>
<tr>
<td>docker image prune --filter &quot;dangling=true&quot;</td>
<td>Remove all dangling images</td>
</tr>
<tr>
<td>docker image prune --filter &quot;label=<label>&quot;</label></td>
<td>Remove images with a specific label</td>
</tr>
<tr>
<td>docker image prune --filter &quot;dangling=false&quot; --filter &quot;label!=<repository>&quot;</repository></td>
<td>Remove images that are not associated with a specific repository</td>
</tr>
<tr>
<td>docker volume prune</td>
<td>Remove all unused volumes</td>
</tr>
<tr>
<td>docker volume prune --filter &quot;dangling=true&quot;</td>
<td>Remove all dangling volumes</td>
</tr>
<tr>
<td>docker volume prune --filter &quot;label=<label>&quot;</label></td>
<td>Remove volumes with a specific label</td>
</tr>
<tr>
<td>docker volume prune --filter &quot;dangling=false&quot; --filter &quot;label!=<container>&quot;</container></td>
<td>Remove volumes that are not associated with a specific container</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p></p><h4 id="what-if-i-delete-an-image">What if I delete an image?!</h4><p>Images are necessary for creating and running containers in Docker. When a container is created, it is based on an image that contains the application code, libraries, and dependencies required to run the application.</p><p>If you delete an image that is being used by a running container, the container will continue to function normally. This is because the container has already loaded the necessary files and libraries into memory, and does not rely on the image file once it is running. However, if you delete an image that is required to create a container, you will not be able to create new containers from that image since it&apos;s no longer on your system but, you can pull it again from a registry or rebuild it from a Dockerfile.</p><p>To pull an image from a registry, you can use the <code>docker pull</code> command followed by the name of the image and its tag (if applicable). For example:</p><pre><code>$ docker pull nginx:latest
</code></pre><p>This will download the latest version of the Nginx image from Docker Hub.</p><p>To rebuild an image from a Dockerfile, you can use the <code>docker build</code> command followed by the path to the Dockerfile. For example:</p><pre><code>$ docker build -t myapp:latest .</code></pre><p>This will build a new image called <code>myapp</code> from the Dockerfile in the current directory.</p><p>Once you have the image, you can use it to create new containers as needed. For example:</p><pre><code>$ docker run -d myapp:latest
</code></pre><p>This will create a new container from the <code>myapp</code> image and run it in the background.</p><p>It&apos;s a good practice to avoid deleting images that are required to create containers. Instead, you can use the <code>docker image prune</code> command to remove unused images that are not associated with any containers or tags. This will help you to free up disk space without affecting your running containers.</p><h2 id="using-filters">Using Filters</h2><p>To limit the objects that will be removed, you can use filters with the <code>docker system prune</code> command. Here are some examples of filters you can use:</p><ul><li><strong>Dangling</strong>: Filter images that are not associated with any container or tag.</li></ul><pre><code>$ docker image prune --filter &quot;dangling=true&quot;
</code></pre><p>The <code>dangling</code> filter option is used to filter images that are not referenced by any container or tag. When an image is created, it is given a unique ID that is used to identify it. If the image is tagged with a name and pushed to a registry or used to create a container, it is no longer considered dangling. However, if the image is not tagged or used to create a container, it is considered dangling and can be removed with the <code>docker image prune</code> command.</p><ul><li><strong>Until</strong>: Filter objects that have not been used in a certain duration.</li></ul><pre><code>$ docker system prune --filter &quot;until=24h&quot;
</code></pre><ul><li><strong>Label</strong>: Filter objects that have a specific label.</li></ul><pre><code>$ docker volume prune --filter &quot;label=myapp&quot;
</code></pre><h2 id="warning">Warning</h2><p>It&apos;s important to note that removing unused objects and running the garbage collector can have unintended consequences. Be sure to review the objects that will be removed before running any of the above commands. Also, removing an image or container will permanently delete it, so be sure to back up any data that you want to keep.</p><h2 id="docker-compose">Docker Compose</h2><p>Docker Compose is a tool for defining and running multi-container Docker applications. It provides a convenient way to manage containers, networks, and volumes, and automates the creation and management of these objects.</p><p>You can use the <code>docker-compose down</code> command to remove all containers, networks, and volumes created by <code>docker-compose up</code>. This command will stop and remove all containers that were created with <code>docker-compose up</code>, as well as any associated networks and volumes.</p><p>Here&apos;s an example <code>docker-compose.yml</code> file that defines a web application with a PostgreSQL database:</p><pre><code>version: &apos;3&apos;
services:
  web:
    image: nginx:latest
    ports:
      - &quot;80:80&quot;
  db:
    image: postgres:latest
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data:
</code></pre><p>This file defines two services, <code>web</code> and <code>db</code>, and creates a named volume called <code>db-data</code> for storing the data of the <code>db</code> service.</p><p>To create and start the containers defined in this file, you can run the following command:</p><pre><code>$ docker-compose up -d
</code></pre><p>This command will start the containers defined in the <code>docker-compose.yml</code> file in detached mode (<code>-d</code>), which means that they will run in the background. To stop and remove the containers created by <code>docker-compose up</code>, you can use the <code>docker-compose down</code> command:</p><pre><code>$ docker-compose down
</code></pre><p>This command will stop and remove all containers created by <code>docker-compose up</code>, as well as any associated networks and volumes. By default, the <code>docker-compose down</code> command will remove only the containers and networks created by <code>docker-compose up</code>. To also remove any volumes that were created by <code>docker-compose up</code>, you can use the <code>--volumes</code> or <code>-v</code> option:</p><pre><code>$ docker-compose down --volumes
</code></pre><p>This command will stop and remove all containers created by <code>docker-compose up</code>, as well as any associated networks and volumes, including named volumes.</p><p>Note that the <code>docker-compose down</code> command will permanently delete all data stored in the volumes associated with the containers that are being removed. Make sure to back up any data that you want to keep before running this command.</p><p>Using Docker Compose with persistent volumes is a good way to ensure that your data is safe and secure even when the containers are removed. By defining named volumes in your <code>docker-compose.yml</code> file, you can store data in a volume that will persist even when the container is removed. This is a good practice for applications that require persistent data storage.</p><p>In conclusion, managing disk space in Docker is an important aspect of Docker administration. By using the tools provided by Docker, such as the <code>docker system prune</code> command and filters, you can remove unused objects and reclaim disk space. Additionally, using Docker Compose with persistent volumes is a good way to ensure that your data is safe and secure even when the containers are removed.</p><h6 id="summary-commands">Summary Commands</h6><!--kg-card-begin: html--><table>
  <thead>
    <tr>
      <th>Command</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>docker system prune</td>
      <td>Remove all unused containers, images, networks, and volumes</td>
    </tr>
    <tr>
      <td>docker image prune</td>
      <td>Remove all unused images</td>
    </tr>
    <tr>
      <td>docker container prune</td>
      <td>Remove all stopped containers</td>
    </tr>
    <tr>
      <td>docker volume prune</td>
      <td>Remove all unused volumes</td>
    </tr>
    <tr>
      <td>docker system prune --filter</td>
      <td>Use filters to limit the objects that will be removed</td>
    </tr>
    <tr>
      <td>docker image rm</td>
      <td>Remove a specific image</td>
    </tr>
    <tr>
      <td>docker-compose up</td>
      <td>Start the containers defined in a Docker Compose file</td>
    </tr>
    <tr>
      <td>docker-compose down</td>
      <td>Stop and remove the containers, networks, and volumes created by Docker Compose</td>
    </tr>
  </tbody>
</table>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Demystifying User Permissions and Access in Linux for Developers]]></title><description><![CDATA[<p>In Linux, permissions and access control are fundamental concepts that govern the security of a system. The users of a Linux system can have different levels of access, depending on their permissions. The root user, also known as the superuser, has unrestricted access to the entire system, while other users</p>]]></description><link>https://www.codinginmedicine.com/demystifying-user-permissions-and-access-in-linux-for-developers/</link><guid isPermaLink="false">63e91b4a205a240001fa9656</guid><category><![CDATA[linux]]></category><category><![CDATA[environments]]></category><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Sun, 12 Feb 2023 17:18:47 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1485230405346-71acb9518d9c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDN8fHNlY3VyaXR5fGVufDB8fHx8MTY3NjIyMjE5MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1485230405346-71acb9518d9c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDN8fHNlY3VyaXR5fGVufDB8fHx8MTY3NjIyMjE5MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Demystifying User Permissions and Access in Linux for Developers"><p>In Linux, permissions and access control are fundamental concepts that govern the security of a system. The users of a Linux system can have different levels of access, depending on their permissions. The root user, also known as the superuser, has unrestricted access to the entire system, while other users have limited access to specific parts of the system.</p><p>In this tutorial, we will discuss the concepts of root and user permissions, access, and privileges in Linux.</p><p><strong>User Accounts</strong></p><p>In Linux, each user has a unique username and user ID (UID). Usernames are used to identify users in the system, while UID is a numeric identifier that is used by the system to determine the user&apos;s access privileges.</p><p>Each user has their own home directory, where they can store their personal files and data. By default, users can only access files and directories that are owned by them, unless they have been granted special permissions.</p><p><strong>Root User</strong></p><p>The root user is a special user account that has unrestricted access to the entire system. The root user has the highest level of permissions in Linux, and can perform any system-level task, such as installing software, modifying system configuration files, and managing system processes.</p><p>However, with great power comes great responsibility. The root user has the ability to make changes that could potentially harm the system, so it should be used with caution. It is generally recommended to use the root user only when it is absolutely necessary, and to perform routine tasks using a regular user account.</p><p><strong>File Permissions</strong></p><p>In Linux, file permissions are used to control access to files and directories. File permissions are divided into three categories: owner, group, and others.</p><p>The owner of a file is the user who created the file, and has full access to the file. The group is a collection of users who share the same access permissions to a file, while others are users who are not the owner or in the group.</p><p>Each category has three types of permissions: read (r), write (w), and execute (x). The read permission allows a user to view the contents of a file, the write permission allows a user to modify the contents of a file, and the execute permission allows a user to run the file as a program.</p><p>To view the permissions of a file, use the ls command with the -l option:</p><pre><code>ls -l filename
</code></pre><p>The output will show the permissions of the file in the following format:</p><pre><code>-rw-r--r-- 1 username groupname size date filename
</code></pre><p>The first character in the output (-) represents the type of file. The next three characters (rw-) represent the permissions of the owner, the next three (r--) represent the permissions of the group, and the final three (r--) represent the permissions of others.</p><p><strong>Changing File Permissions</strong></p><p>To change the file permissions, you can use the chmod command. The chmod command changes the permissions of a file or directory.</p><p>The syntax of the chmod command is as follows:</p><pre><code>chmod [options] mode file
</code></pre><p>The options are:</p><ul><li>-r : recursively change permissions of all files and subdirectories within the specified directory</li><li>-v : verbose mode, displays the permissions of each file after it has been changed</li><li>-c : changes only those files whose permissions have actually been changed</li></ul><p>The mode is a three-digit number that represents the new permissions of the file. The first digit represents the owner&apos;s permissions, the second digit represents the group&apos;s permissions, and the third digit represents the permissions of others. Each digit is calculated by adding the values of the read (4), write (2), and execute (1) permissions.</p><p>For example, to give the owner full permissions, the group read and execute permissions, and others no permissions, you can use the following command:</p><pre><code>chmod 750 filename</code></pre><p>The 7 represents the sum of the read, write, and execute permissions for the owner (4+2+1=7), the 5 represents the sum of the read and execute permissions for the group (4+1=5), and the 0 represents no permissions for others. Alternatively, you can use the letters r, w, and x to represent the permissions. For example, to give the owner full permissions, the group read and execute permissions, and others no permissions, you can use the following command: </p><pre><code>chmod u=rwx,g=rx,o= filename</code></pre><p>The u stands for owner, g stands forgroup, and o stands for others. The rwx stands for read, write, andexecute, while the rx stands for read and execute. </p><p><strong>UserGroups</strong></p><p>In Linux, user groups are used to assign permissions to multiple users at once. A user can be a member of multiple groups, and each group can have its own setof permissions. To create a new group, you can use the groupadd command</p><pre><code>groupadd groupname</code></pre><p>To add a user to a group, you can use the usermod command:</p><pre><code>usermod -a -G groupname username
</code></pre><p>The -a option adds the user to the group, while the -G option specifies the group.</p><p><strong>Sudo</strong></p><p>In Linux, the sudo command allows a user to execute commands with the permissions of the root user. This can be useful for performing tasks that require root privileges, without actually logging in as the root user.</p><p>To use the sudo command, simply prefix the command with sudo:</p><pre><code>sudo command
</code></pre><p>You will be prompted for your password, and if it is correct, the command will be executed with root privileges.</p><p><strong>Conclusion</strong></p><p>The concepts of user permissions, access, and privileges are important not only on a single Linux workstation, but also on different types of servers, and even in Docker containers. In a multi-user environment, where multiple users are accessing the same system or application, it is important to restrict access to certain resources and data to prevent unauthorized modifications or breaches. Similarly, in server environments, managing user access and permissions is crucial for controlling who can access the server and what actions they can perform. With the increasing popularity of containerization technologies like Docker, managing user permissions and access is also important in containerized environments. In Docker, users can be assigned different permissions within the container, and the host system can restrict access to certain system resources, providing an added layer of security. By understanding user permissions and access in Linux, developers can ensure the safety and stability of their applications across different types of systems and environments.</p><!--kg-card-begin: html--><table>
  <tr>
    <th>Command</th>
    <th>Option</th>
    <th>Output</th>
  </tr>
  <tr>
    <td>whoami</td>
    <td></td>
    <td>Displays the current user&apos;s username</td>
  </tr>
  <tr>
    <td>id</td>
    <td></td>
    <td>Displays the current user&apos;s UID, GID, and group membership</td>
  </tr>
  <tr>
    <td>su</td>
    <td></td>
    <td>Allows the current user to switch to the root user</td>
  </tr>
  <tr>
    <td>su</td>
    <td>- username</td>
    <td>Allows the current user to switch to the specified user</td>
  </tr>
  <tr>
    <td>sudo</td>
    <td></td>
    <td>Executes a command with root-level privileges</td>
  </tr>
  <tr>
    <td>sudo</td>
    <td>-u username</td>
    <td>Executes a command with the privileges of the specified user</td>
  </tr>
  <tr>
    <td>adduser</td>
    <td>username</td>
    <td>Creates a new user with the specified username</td>
  </tr>
  <tr>
    <td>usermod</td>
    <td>-a -G groupname username</td>
    <td>Adds the user to the specified group</td>
  </tr>
  <tr>
    <td>groupadd</td>
    <td>groupname</td>
    <td>Creates a new group with the specified name</td>
  </tr>
  <tr>
    <td>chown</td>
    <td>username:groupname filename</td>
    <td>Changes the owner and group of the specified file</td>
  </tr>
  <tr>
    <td>chmod</td>
    <td>mode filename</td>
    <td>Changes the permissions of the specified file</td>
  </tr>
</table><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Mastering Time: A Beginner's Guide to Date and Time Manipulation in Python]]></title><description><![CDATA[<p>Sooner or later, during your coding journey, you are going to come across the need to manipulate time and dates. Especially if you deal with medical records as every entry, assessment, treatment, etc, should have a time and date associated with it. Different environment and languages have their own specific</p>]]></description><link>https://www.codinginmedicine.com/mastering-time-a-beginners-guide-to-date-and-time-manipulation-in-python/</link><guid isPermaLink="false">63d557936bdb5d0001254e63</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Fri, 10 Feb 2023 16:10:29 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fHRpbWV8ZW58MHx8fHwxNjc0OTI1OTc5&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1501139083538-0139583c060f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fHRpbWV8ZW58MHx8fHwxNjc0OTI1OTc5&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Mastering Time: A Beginner&apos;s Guide to Date and Time Manipulation in Python"><p>Sooner or later, during your coding journey, you are going to come across the need to manipulate time and dates. Especially if you deal with medical records as every entry, assessment, treatment, etc, should have a time and date associated with it. Different environment and languages have their own specific quirks(I&apos;m looking at you SAS) when it comes to handling these aspects, and in this article, we are going to talk about python&apos;s modules for handling such objects. Python has a built-in module called <code>datetime</code> that provides the necessary classes and functions to work with dates and times. However, there are other third-party packages like <code>dateutil</code>, <code>pytz</code>, and <code>pendulum</code> that can make working with dates and times even easier. We will start with the datetime module first. </p><p>The <code>datetime</code> module provides the <code>datetime</code> class, which can be used to represent a specific point in time. The <code>datetime</code> class takes three arguments: the year, the month, and the day. For example:</p><pre><code class="language-python">from datetime import datetime
now = datetime(2022, 12, 1)
print(now)
# Output: 2022-12-01 00:00:00
</code></pre><p>The <code>datetime</code> module also provides the <code>date</code> class, which can be used to represent a specific date without a time. The <code>date</code> class takes three arguments: the year, the month, and the day. For example:</p><pre><code class="language-python">from datetime import date
today = date.today()
print(today)
# Output: 2022-12-01
</code></pre><p>You can also use the <code>datetime.now()</code> function to get the current date and time, and the <code>datetime.utcnow()</code> function to get the current date and time in UTC.</p><p>The <code>datetime</code> module also provides the <code>timedelta</code> class, which can be used to represent a duration of time. The <code>timedelta</code> class takes several arguments, such as days, seconds, microseconds, milliseconds, minutes, hours, and weeks.</p><p>For example, to get the date and time one day from now:</p><pre><code class="language-python">from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
print(tomorrow)
# Output: 2022-12-02 10:15:30.283740
</code></pre><p>You can also subtract <code>timedelta</code> from <code>datetime</code> to get the date and time before.</p><p>To get rid of the time component in a datetime object, you can use the <code>date()</code> method, which returns a date object with the same year, month, and day as the datetime object.</p><p>For example:</p><pre><code class="language-python">from datetime import datetime
now = datetime.now()
print(now)
# Output: 2022-12-01 10:15:30.283740
date_only = now.date()
print(date_only)
# Output: 2022-12-01
</code></pre><p>To output a date in a human-readable format, you can use the <code>strftime()</code> method, which allows you to format the date and time using codes that represent the various components of the date and time.</p><p>For example, to output a date in the format &quot;YYYY-MM-DD&quot;:</p><pre><code class="language-python">now = datetime.now()
print(now.strftime(&quot;%Y-%m-%d&quot;))
# Output: 2022-12-01
</code></pre><p>But as mentioned before python&apos;s <code>datetime</code> module has its limitations, so developers often use third party packages like <code>dateutil</code> , <code>pytz</code>, <code>pendulum</code> to work with dates and times.</p><p>The <code>dateutil</code> package provides a <code>parser.parse()</code> method that can parse almost any string representation of date and time, and also includes a <code>relativedelta()</code> function that can be used to perform arithmetic operations with dates and times.</p><p>For example, to format a date in the format &quot;YYYY-MM-DD&quot; using the dateutil package:</p><pre><code class="language-python">from dateutil import parser
now = parser.parse(&quot;2022-12-01&quot;)
print(now.strftime(&quot;%Y-%m-%d&quot;))
# Output: 2022-12-01
</code></pre><p>Another package for date and time manipulation is <code>pytz</code>, which provides the timezone information.</p><pre><code class="language-python">import pytz
now = datetime.now(pytz.UTC)
</code></pre><p>This will give you the date and time in UTC format.</p><p><code>pendulum</code> is another package that provides simple, easy-to-use, and Pythonic methods for creating, manipulating, formatting, and parsing dates and times. It also includes timezone support and advanced features such as period arithmetic, recurrences, and humanization.</p><pre><code class="language-python">import pendulum
now = pendulum.now()
print(now.to_date_string())
</code></pre><p>This will give you the date in string format &apos;YYYY-MM-DD&apos;</p><h5 id="datetime-syntax-table">Datetime syntax table</h5><!--kg-card-begin: html--><table>
  <tr>
    <th>Code</th>
    <th>Explanation</th>
    <th>Output (example)</th>
  </tr>
  <tr>
    <td>%a</td>
    <td>Abbreviated weekday name</td>
    <td>Mon</td>
  </tr>
  <tr>
    <td>%A</td>
    <td>Full weekday name</td>
    <td>Monday</td>
  </tr>
  <tr>
    <td>%b</td>
    <td>Abbreviated month name</td>
    <td>Dec</td>
  </tr>
  <tr>
    <td>%B</td>
    <td>Full month name</td>
    <td>December</td>
  </tr>
  <tr>
    <td>%d</td>
    <td>Day of the month (zero-padded)</td>
    <td>01</td>
  </tr>
  <tr>
    <td>%m</td>
    <td>Month of the year (zero-padded)</td>
    <td>12</td>
  </tr>
  <tr>
    <td>%Y</td>
    <td>Year with century</td>
    <td>2022</td>
  </tr>
  <tr>
    <td>%H</td>
    <td>Hour (24-hour format)</td>
    <td>00</td>
  </tr>
  <tr>
    <td>%I</td>
    <td>Hour (12-hour format)</td>
    <td>12</td>
  </tr>
  <tr>
    <td>%M</td>
    <td>Minute</td>
    <td>30</td>
  </tr>
  <tr>
    <td>%S</td>
    <td>Second</td>
    <td>45</td>
  </tr>
</table>
<!--kg-card-end: html--><p></p><p>In conclusion, python&apos;s <code>datetime</code> module provides the necessary classes and functions to work with dates and times, but third-party packages like <code>dateutil</code>, <code>pytz</code>, and <code>pendulum</code> can make working with dates and times even easier. These packages provide additional features such as parsing and formatting dates, timezone support, and advanced features such as period arithmetic, recurrences, and humanization. It is recommended to choose the package that best fits your requirements and use the appropriate methods to format your date and time.</p><p>Of course, this is just the tip of the iceberg. For a deeper dive check out these links to libraries:</p><ul><li><code>datetime</code>: <a href="https://docs.python.org/3/library/datetime.html">https://docs.python.org/3/library/datetime.html</a></li><li><code>dateutil</code>: <a href="https://dateutil.readthedocs.io/en/stable/">https://dateutil.readthedocs.io/en/stable/</a></li><li><code>pytz</code>: <a href="https://pythonhosted.org/pytz/">https://pythonhosted.org/pytz/</a></li><li><code>pendulum</code>: <a href="https://pendulum.eustace.io/docs/">https://pendulum.eustace.io/docs/</a></li></ul><p></p><p>-- Stay tuned for Part 2 of this time series for R</p>]]></content:encoded></item><item><title><![CDATA[Crafting Effective Prompts for AI-Generated Text]]></title><description><![CDATA[<p>Prompt engineering is a critical aspect of natural language processing (NLP) and is central to the development of language models. By carefully designing prompts, we can influence the outputs generated by language models and guide them to generate text that is on-topic, coherent, and readable. Whether you are working on</p>]]></description><link>https://www.codinginmedicine.com/crafting-effective-prompts-for-ai-generated-tex/</link><guid isPermaLink="false">63dd9d8f272b310001f3af14</guid><dc:creator><![CDATA[Gyasi Sutton, MD, MPH]]></dc:creator><pubDate>Mon, 06 Feb 2023 00:47:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1583443920098-6b56d6aabdb1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDUxfHxhaSUyMHRleHR8ZW58MHx8fHwxNjc1NDcwOTc3&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1583443920098-6b56d6aabdb1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDUxfHxhaSUyMHRleHR8ZW58MHx8fHwxNjc1NDcwOTc3&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Crafting Effective Prompts for AI-Generated Text"><p>Prompt engineering is a critical aspect of natural language processing (NLP) and is central to the development of language models. By carefully designing prompts, we can influence the outputs generated by language models and guide them to generate text that is on-topic, coherent, and readable. Whether you are working on a conversational AI system, a text generation tool, or any other NLP project, having a solid understanding of prompt engineering is essential. In this tutorial, we will explore the various techniques and strategies used in prompt engineering, including the use of escape characters, structure keys, and readability keys. Whether you are a seasoned NLP practitioner or just getting started with language models, this tutorial will provide you with the knowledge and skills needed to create effective and meaningful prompts for your NLP projects.</p><p>Please note that the information and explanations provided in this tutorial are general guidelines for most NLP models and may work for some image models as well. However, it is important to always read the API documentation for the specific model you are using to understand the exact commands and syntax for prompts. The features and tools available for prompt engineering can vary greatly between different models and APIs, so it is essential to consult the documentation for the specific model you are using to ensure that you are using the correct syntax and commands.</p><p>Use these guidelines when generating a prompt:</p><p>1.	Understanding the task: To get started with prompt engineering using ChatGPT, it&apos;s 		essential to have a clear understanding of the task you want the model to perform. 		For example, let&apos;s say you want the model to generate a weather report for a specific 		location and date.<br><br>2.	Defining the prompt format: In this case, the prompt format could include a prompt 		header and a prompt body. The header could provide a high-level overview of the 		task, for example: &quot;Generate a weather report for [location] on [date].&quot; The prompt 		body could provide more specific details and constraints, such as the desired format 		of the report or any additional information to include.</p><p>3. 	Crafting the prompt: When writing the prompt, consider the following points: </p><p>		a.	Keep it concise: A clear, concise prompt is easier for the model to understand and 		generates more consistent outputs. For example:</p><p>		<code>Generate a weather report for New York City on February 3rd, 2023:</code></p><p>		b.	Use clear language: Use simple, straightforward language to minimize ambiguity 		and reduce the chance of the model producing unexpected results. For example:</p><p>		<code>Generate a weather report for New York City, USA on February 3rd, 2023:</code></p><p>		c.	Provide context: Provide enough context for the model to understand the task and 		the context in which it is being performed. For example:</p><p>		<code>Generate a brief weather report for New York City, USA on February 3rd, 			2023 including current temperature and any precipitation.</code></p><p>		d.	Include examples: Including examples can help illustrate the desired output 		 &#xA0; &#xA0; &#xA0; &#xA0; and provide a reference for the model. For example:</p><pre><code>Generate a brief weather report for New York City, USA on February 3rd, 2023 including current temperature and any precipitation:

Example:
The current temperature in New York City, USA is 47&#xB0;F with light rain.
</code></pre><p>4. 	Iterating on the prompt: Once you have a draft of the prompt, test it with the model to 		see how it performs. If you&apos;re not happy with the outputs, refine the prompt until you 		get the desired results. Repeat this process until you&apos;re satisfied with the results.</p><h4 id="iteration-an-important-process">Iteration, an Important process</h4><p>Iteration is a critical component of the prompt engineering process. Essentially, it 		involves refining and improving your prompt over time, until you achieve the desired 		results. The goal of iterating on the prompt is to optimize the language model&apos;s 		performance and generate outputs that are coherent, on-topic, and readable. To 		do this, you&apos;ll need to test your prompt with the model and observe the outputs it generates. Based on this, you can then make changes to the prompt and re-test it, until you get the results you want.</p><p>The iterative process can involve fine-tuning the wording, adjusting the structure, and adding or removing specific elements. For example, you might start by crafting a basic prompt that outlines the topic and provides some context. Then, you can iterate on the prompt by adding specific details, adjusting the tone, or incorporating relevant keywords. The more you iterate, the better you&apos;ll understand what works and what doesn&apos;t, and you&apos;ll be able to refine the prompt accordingly.</p><p>The process of iterating on the prompt can be time-consuming, but it&apos;s well worth the effort. By investing time and effort into the prompt engineering process, you can greatly improve the quality and consistency of the outputs generated by your language model, and ultimately deliver better results for your NLP project</p><h4 id="punctuation">Punctuation</h4><p>It&apos;s important to consider the use of punctuation and special characters when creating prompts for language models like ChatGPT. Here are some tips:</p><ol><li>Use clear and consistent punctuation: Using clear and consistent punctuation can help reduce ambiguity and improve the readability of your prompt. For example, always use a colon after the header to separate it from the body of the prompt.</li><li>Avoid complex punctuation: Complex punctuation such as multiple exclamation points or long strings of punctuation marks can be confusing and difficult for the model to parse. Stick to straightforward punctuation such as periods, commas, and colons.</li><li>Use special characters with caution: Some special characters, such as emojis or mathematical symbols, may not be supported by the model or may be interpreted differently than intended. If you need to include special characters, consider using plain text representations instead.</li></ol><h4 id="example-prompts">Example Prompts </h4><ol><li>A bullet point list of ingredients for a recipe:</li></ol><p><code>Generate a recipe for spaghetti carbonara: </code><br><br><code>- spaghetti</code><br><code>- pancetta or bacon</code><br><code>- eggs</code><br><code>- parmesan cheese</code><br><code>- black pepper</code></p><p>2.	A prompt for a math problem with parentheses and symbols:</p><p><code>Solve the following equation:</code></p><p><code>(2x + 3) * (x - 4) = 0</code></p><p>3.	A prompt for statistical analysis with a table:</p><p><code>Perform a t-test on the following data to determine if there is a significant difference in the mean weight of two species of fish: </code></p><p><code>Species 1: 40g &#xA0; 45g &#xA0; 50g &#xA0; 55g &#xA0; 60g Species 2: 50g &#xA0; 55g &#xA0; 60g &#xA0; 65g &#xA0; 70g</code></p><p>4.	A prompt for a short story or creative writing:</p><p><code>Write a short story about a character named Maria who discovers a mysterious object: </code></p><p><code>Maria was on a walk in the park when she stumbled upon a shiny object hidden in the grass. At first, she thought it was just a piece of trash, but as she picked it up, she realized it was a beautiful and intricate object unlike anything she had ever seen before.</code></p><p>5.	A prompt for a historical event with dates and locations:</p><p><code>Write a brief summary of the events of the Battle of Gettysburg, fought July 1-3, 1863: </code></p><p><code>The Battle of Gettysburg was a decisive battle of the American Civil War, fought between the Union and Confederate forces in and around the town of Gettysburg, Pennsylvania. Over the course of three days, the Union army successfully repulsed repeated Confederate attacks, leading to a Union victory and a turning point in the war.</code></p><h3 id="coaxing-the-last-bit-of-info">Coaxing the last bit of info</h3><p><strong>Escape characters</strong> are used to represent special characters or sequences that have a specific meaning in the input syntax and you can create more complex and readable prompts for your language model. Here&apos;s how you can add escape characters to a prompt:</p><ol><li>Backslash (<code>\</code>): In most prompt inputs, the backslash is used as an escape character. To include a literal backslash in your prompt, you need to escape it by adding another backslash before it, like so: <code>\\</code>.</li><li>Newline (<code>\n</code>): To add a newline character to your prompt, you can use the escape sequence <code>\n</code>. This will cause the text that follows to be displayed on a new line.</li><li>Tab (<code>\t</code>): To add a tab character to your prompt, you can use the escape sequence <code>\t</code>. This will cause the text that follows to be indented.</li><li>Quotes (<code>\&apos;</code> or <code>\&quot;</code>): To include a quote character in your prompt, you can escape it by adding a backslash before it. For single quotes, use <code>\&apos;</code>, and for double quotes, use <code>\&quot;</code>.</li></ol><!--kg-card-begin: html--><table>
  <tr>
    <th>Character</th>
    <th>Description</th>
  </tr>
  <tr>
    <td>\</td>
    <td>Backslash (escape character)</td>
  </tr>
  <tr>
    <td>\n</td>
    <td>Newline</td>
  </tr>
  <tr>
    <td>\t</td>
    <td>Tab</td>
  </tr>
  <tr>
    <td>\&apos;</td>
    <td>Single quote</td>
  </tr>
  <tr>
    <td>\&quot;</td>
    <td>Double quote</td>
  </tr>
</table>
<!--kg-card-end: html--><p>In some prompt inputs, you may want to add themes or structures to guide the output and make it more coherent. Here&apos;s how you can do that:</p><ol><li>Templates: One way to add structure to the output is to provide a template that the language model should follow. For example, if you are generating a recipe, you can provide a template with placeholders for ingredients, instructions, and serving information. The language model will then fill in the placeholders with the corresponding information.</li><li>Keywords: Another way to add themes to the output is to provide keywords or phrases that should appear in the output. This can help guide the language model to generate outputs that are on topic and coherent.</li><li>Grammar and syntax: You can also add structure to the output by specifying the grammar and syntax that should be used. For example, you can specify that the output should be written in a specific tense (e.g., present or past), or that it should follow a specific sentence structure (e.g., subject-verb-object).</li></ol><p>Here&apos;s an example of a prompt with a template for a recipe:</p><pre><code>Generate a recipe for a chocolate cake:

Ingredients:
- [x] cups of all-purpose flour
- [x] cups of granulated sugar
- [x] cups of unsweetened cocoa powder
- [x] teaspoons of baking powder
- [x] teaspoons of baking soda
- [x] teaspoons of salt
- [x] large eggs
- [x] cups of buttermilk
- [x] cups of warm water
- [x] cups of vegetable oil

Instructions:
1. Preheat the oven to [x]&#xB0;F.
2. In a large bowl, whisk together the flour, sugar, cocoa powder, baking powder, baking soda, and salt.
3. In a separate bowl, beat the eggs, buttermilk, warm water, and vegetable oil.
4. Pour the wet ingredients into the dry ingredients and stir until just combined.
5. Pour the batter into a greased [x]-inch round cake pan.
6. Bake for [x] minutes, or until a toothpick inserted into the center of the cake comes out clean.
7. Let the cake cool for [x] minutes, then remove from the pan and transfer to a wire rack to cool completely.

Serving Information:
Serves [x] people.
</code></pre><p>By using templates, keywords, and syntax, you can help guide the language model to generate outputs that are more coherent and on topic, and that follow the structure and style that you desire.</p><h4 id="conclusion">Conclusion</h4><p>In conclusion, prompt engineering is the process of designing and crafting effective prompts for language models to generate high-quality and coherent outputs. To achieve this goal, you can use techniques such as templates, keywords, and grammar/syntax to add structure and themes to the output.</p><p>In this tutorial, we covered the basics of prompt engineering and how to design effective prompts for language models. We discussed the importance of having a clear goal for the output, and how to use templates, keywords, and grammar/syntax to control the output. We also summarized the key concepts in a summary table and cheat sheet for quick reference.</p><p>Overall, prompt engineering is an important aspect of working with language models, as it allows you to control the quality and coherence of the outputs and get the results you need for your applications. Whether you are working on a specific project or simply exploring the capabilities of language models, prompt engineering is a valuable tool to have in your toolkit.</p><h4 id="summary">Summary</h4><p>Here&apos;s a <strong>cheat sheet</strong> for prompt engineering:</p><ol><li>Start by defining the goal of your prompt and what you want the output to be (e.g., a recipe, a story, a summary).</li><li>Consider using templates, keywords, and syntax to add structure and themes to the output.</li><li>Test and refine your prompt until you are satisfied with the quality and coherence of the outputs.</li></ol><!--kg-card-begin: html--><table>
  <tr>
    <th>Concept</th>
    <th>Description</th>
  </tr>
  <tr>
    <td>Prompt engineering</td>
    <td>The process of designing and crafting effective prompts for language models, in order to generate high-quality and coherent outputs.</td>
  </tr>
  <tr>
    <td>Templates</td>
    <td>A way to add structure to the output by providing a template that the language model should follow.</td>
  </tr>
  <tr>
    <td>Keywords</td>
    <td>A way to add themes to the output by providing keywords or phrases that should appear in the output.</td>
  </tr>
  <tr>
    <td>Grammar and syntax</td>
    <td>A way to add structure to the output by specifying the grammar and syntax that should be used.</td>
  </tr>
</table>
<!--kg-card-end: html--><p>Remember, the specific features and tools available for prompt engineering will depend on the specific language model you are using, so be sure to consult the documentation for more information.</p>]]></content:encoded></item></channel></rss>