<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>REBELSCIENCE</title><link>https://rebelscience.club/</link><description>Bioinformatics, Programming and Open-Source Science</description><item><title>Genome Toolkit. Part 4.3: Building Validated Biological Models</title><link>https://rebelscience.club/2026/08/genome-toolkit-part-4-3-building-validated-biological-models/</link><guid isPermaLink="true">https://rebelscience.club/2026/08/genome-toolkit-part-4-3-building-validated-biological-models/</guid><pubDate>Sat, 29 Aug 2026 11:09:00 GMT</pubDate><description>In Part 4.3, we introduce Genome Toolkit’s first validated biological sequence models. We build a reusable Sequence base model and a DNA-specific model that normalizes sequences and rejects invalid nucleotide symbols. We then connect validated DNA to our existing application.py while keeping the k-mer algorithms and scientific calculations unchanged. This gives Genome Toolkit its first real biological validation layer without disrupting the working project we already built.
</description><content:encoded><![CDATA[
<p class="wp-block-paragraph">Welcome back to the Genome Toolkit series!</p>



<p class="wp-block-paragraph">In Part 4.2, we modernized our existing project without throwing away the scientific work we had already done. Genome Toolkit is now an installable Python package managed with <code>uv</code>, and our two k-mer algorithms already live inside:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">src/genome_toolkit/algorithms/</pre></div>



<p class="wp-block-paragraph">Most importantly, our application still produces exactly the same scientific results as before.</p>



<p class="wp-block-paragraph">But we ended Part 4.2 with one important problem. Our algorithms still accept an ordinary Python string:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence: str</pre></div>



<p class="wp-block-paragraph">And a Python string can contain almost anything:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">AATTTTAAAAC
HELLO
12345
???</pre></div>



<p class="wp-block-paragraph">Python knows that all four examples are strings. It does not know that only one of them looks like DNA.</p>



<p class="wp-block-paragraph">In this part, we are going to add that biological knowledge to Genome Toolkit.</p>



<p class="wp-block-paragraph">We will create a reusable <code>Sequence</code> model, build a <code>DNA</code> model on top of it, validate real DNA symbols, test both valid and invalid sequences, and then connect the new model to our existing <code>application.py</code> with only a very small change.</p>



<p class="wp-block-paragraph">Our k-mer algorithms are already here and already work. We are not replacing them or bringing them back. We are simply adding a validated biological step before the existing algorithms receive their sequence.</p>



<p class="wp-block-paragraph">The new flow will be:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">ordinary Python string
        ↓
DNA(...)
        ↓
validated DNA
        ↓
dna.sequence
        ↓
our existing k-mer algorithms</pre></div>



<p class="wp-block-paragraph">Later, we will make the connection between our biological models and algorithms even stronger. For now, we will keep the change deliberately small.</p>



<h2 class="wp-block-heading">Starting With Our Working Project</h2>



<p class="wp-block-paragraph">We continue from exactly where Part 4.2 finished.</p>



<p class="wp-block-paragraph">Our project currently looks like this:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">genome_toolkit/
├── .git/
├── .gitignore
├── .venv/
├── README.md
├── application.py
├── pyproject.toml
├── uv.lock
└── src/
    └── genome_toolkit/
        ├── __init__.py
        ├── py.typed
        └── algorithms/
            ├── __init__.py
            └── kmer.py</pre></div>



<p class="wp-block-paragraph">Notice that our algorithms are already part of the package:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">src/genome_toolkit/algorithms/</pre></div>



<p class="wp-block-paragraph">And our current <code>application.py</code> is still the familiar example from Part 4.2:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.algorithms import (
    count_kmer,
    find_most_frequent_kmers,
)

seq = &quot;AATTTTAAAAC&quot;
kmer = &quot;AA&quot;
k_len = 3


print(f&quot;Sequence: {seq}&quot;)
print(f&quot;k-mer: {kmer}&quot;)
print(f&quot;Repeats found: {count_kmer(seq, kmer)}&quot;)
print(f&quot;Most frequent k-mer: {find_most_frequent_kmers(seq, k_len)}&quot;)</pre></div>



<p class="wp-block-paragraph">Running it gives us:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Sequence: AATTTTAAAAC
k-mer: AA
Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">This is our working checkpoint again.</p>



<p class="wp-block-paragraph">We want to finish Part 4.3 with the same k-mer calculations and the same result. The difference will be that the sequence reaching those algorithms will first pass through our new DNA validation.</p>



<h2 class="wp-block-heading">What Are We Going to Add?</h2>



<p class="wp-block-paragraph">We are going to add one new package inside Genome Toolkit:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">sequence/
├── __init__.py
├── base.py
└── dna.py</pre></div>



<p class="wp-block-paragraph">Each file has one clear job:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">base.py
    ↓
shared biological sequence structure

dna.py
    ↓
DNA-specific normalization and validation

__init__.py
    ↓
clean public imports</pre></div>



<p class="wp-block-paragraph">The important point is what we are <strong>not</strong> changing.</p>



<p class="wp-block-paragraph">Our existing:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">algorithms/
├── __init__.py
└── kmer.py</pre></div>



<p class="wp-block-paragraph">stays in place.</p>



<p class="wp-block-paragraph">We are adding a new biological layer alongside our existing algorithms, not rebuilding the project again.</p>



<h2 class="wp-block-heading">Why Do We Need Biological Models?</h2>



<p class="wp-block-paragraph">Right now, this is perfectly valid Python:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">seq = &quot;HELLO&quot;</pre></div>



<p class="wp-block-paragraph">And because our k-mer algorithms currently accept a string, Python would happily allow us to pass that string into them.</p>



<p class="wp-block-paragraph">The problem is not Python. <code>"HELLO"</code> really is a valid Python string.</p>



<p class="wp-block-paragraph">The problem is that our program has no biological rule saying:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">This value is supposed to represent DNA.</p>
</blockquote>



<p class="wp-block-paragraph">We could manually write checks everywhere we use a sequence:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">if not set(sequence.upper()).issubset(set(&quot;ACGTN&quot;)):
    raise ValueError(&quot;Sequence contains invalid DNA symbols.&quot;)</pre></div>



<p class="wp-block-paragraph">This checks whether every symbol in the sequence belongs to our allowed DNA alphabet:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">A, C, G, T, N</pre></div>



<p class="wp-block-paragraph">So:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence = &quot;AATTTTAAAAC&quot;</pre></div>



<p class="wp-block-paragraph">would pass, while:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence = &quot;AATTTTZAAAC&quot;</pre></div>



<p class="wp-block-paragraph">would fail because <code>Z</code> is not part of our supported DNA alphabet.</p>



<p class="wp-block-paragraph">But then every time we need to check whether a DNA sequence is valid, we would have to write the same validation code again.</p>



<p class="wp-block-paragraph">Instead, we want one clear boundary:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">untrusted/raw value
        ↓
DNA(...)
        ↓
valid biological object</pre></div>



<p class="wp-block-paragraph">If a <code>DNA</code> object exists successfully, the rest of our program can know that its sequence has already passed the DNA rules we defined.</p>



<p class="wp-block-paragraph">That is the problem we are solving in this part.</p>



<h2 class="wp-block-heading">Adding Pydantic</h2>



<p class="wp-block-paragraph">To build these models, we are going to use <strong>Pydantic</strong>.</p>



<p class="wp-block-paragraph">Pydantic is a Python data-validation library. It lets us describe what data our model should contain and add our own biological validation rules without writing all of the surrounding validation machinery ourselves.</p>



<p class="wp-block-paragraph">For Genome Toolkit, it will help us with things such as:</p>



<ul class="wp-block-list">
<li>required fields;</li>



<li>minimum string lengths;</li>



<li>rejecting unexpected fields;</li>



<li>immutable model objects;</li>



<li>useful validation errors;</li>



<li>type information;</li>



<li>dictionary and JSON serialization.</li>
</ul>



<p class="wp-block-paragraph">We still define the biology ourselves. Pydantic gives us a standard way to apply those rules every time we create a model, instead of writing the same validation code in different parts of the project.</p>



<p class="wp-block-paragraph">And of course, as always, our good friend Corey Schafer has us covered here too. He has an excellent video explaining what Pydantic is and how it works, and I definitely recommend watching it:</p>



<p class="wp-block-paragraph"><strong><a href="https://youtu.be/M81pfi64eeM">Pydantic &#8211; Data Validation for Python</a></strong></p>



<p class="wp-block-paragraph">Pydantic is useful far beyond Genome Toolkit. It is a great way to keep Python projects structured, validated, and easier to extend later into things like web applications, APIs, and AI or agent-based tools.</p>



<p class="wp-block-paragraph">Open a terminal in the Genome Toolkit project directory and add Pydantic:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Shell&quot;,&quot;language&quot;:&quot;Shell&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;shell&quot;}">uv add pydantic</pre></div>



<p class="wp-block-paragraph">Because we are using <code>uv</code>, this command updates both:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">pyproject.toml
uv.lock</pre></div>



<p class="wp-block-paragraph">If we open <code>pyproject.toml</code>, we should now see our first project dependency added:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;toml&quot;,&quot;mime&quot;:&quot;text/x-toml&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;TOML&quot;,&quot;language&quot;:&quot;TOML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;toml&quot;}">dependencies = [
    &quot;pydantic&gt;=2.13.5&quot;,
]</pre></div>



<p class="wp-block-paragraph">The exact version may be newer depending on when you run the command, but the important change is that Pydantic now appears inside our project dependencies. <code>uv.lock</code> is updated automatically with the exact resolved package versions used by our environment.</p>



<p class="wp-block-paragraph">Our package now has its first external runtime dependency because we finally have code that actually needs one.</p>



<h2 class="wp-block-heading">Creating the <code>sequence</code> Package</h2>



<p class="wp-block-paragraph">Inside:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">src/genome_toolkit/</pre></div>



<p class="wp-block-paragraph">create a new folder:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">sequence/</pre></div>



<p class="wp-block-paragraph">We are going to build this package one file at a time. The first file we need is:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">base.py</pre></div>



<p class="wp-block-paragraph">So our project now becomes:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">genome_toolkit/
├── .git/
├── .gitignore
├── .venv/
├── README.md
├── application.py
├── pyproject.toml
├── uv.lock
└── src/
    └── genome_toolkit/
        ├── __init__.py
        ├── py.typed
        ├── algorithms/
        │   ├── __init__.py
        │   └── kmer.py
        └── sequence/            ← NEW
            └── base.py          ← NEW</pre></div>



<p class="wp-block-paragraph">Our existing <code>algorithms/</code> package stays exactly where Part 4.2 left it. We are simply adding a new place for biological sequence models.</p>



<h2 class="wp-block-heading">Starting Our Base <code>Sequence</code> Model</h2>



<p class="wp-block-paragraph">Open:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">src/genome_toolkit/sequence/base.py</pre></div>



<p class="wp-block-paragraph">We will begin with the smallest useful version of our new class:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">&quot;&quot;&quot;Base models for biological sequences.&quot;&quot;&quot;

from pydantic import BaseModel, ConfigDict


class Sequence(BaseModel):
    &quot;&quot;&quot;Base model shared by biological sequence types.&quot;&quot;&quot;

    model_config = ConfigDict(
        frozen=True,
        extra=&quot;forbid&quot;,
        str_strip_whitespace=True,
    )</pre></div>



<p class="wp-block-paragraph">The first important part is:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">class Sequence(BaseModel):</pre></div>



<p class="wp-block-paragraph"><code>BaseModel</code> is Pydantic&#8217;s base class. By inheriting from it, our normal Python class becomes a Pydantic model that can validate the data we give it.</p>



<p class="wp-block-paragraph">Then we configure how our model should behave:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">model_config = ConfigDict(
    frozen=True,
    extra=&quot;forbid&quot;,
    str_strip_whitespace=True,
)</pre></div>



<p class="wp-block-paragraph">We do not call <code>model_config</code> ourselves anywhere else in the code.</p>



<p class="wp-block-paragraph">Because <code>Sequence</code> inherits from Pydantic&#8217;s <code>BaseModel</code>, Pydantic automatically looks for:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">model_config = ConfigDict(...)</pre></div>



<p class="wp-block-paragraph">when it creates and validates a <code>Sequence</code> object.</p>



<p class="wp-block-paragraph">So later, when we write:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence = Sequence(
    identifier=&quot;  example_sequence  &quot;,
    sequence=&quot;AATTTTAAAAC&quot;,
)</pre></div>



<p class="wp-block-paragraph">Pydantic automatically applies the rules from <code>model_config</code> while creating that object.</p>



<p class="wp-block-paragraph">In our case, those rules tell it to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">frozen=True                 → prevent fields from being changed later
extra=&quot;forbid&quot;              → reject fields we did not define
str_strip_whitespace=True   → remove surrounding whitespace from strings</pre></div>



<p class="wp-block-paragraph">So <code>model_config</code> is the place where we define the general behavior that every <code>Sequence</code> object should follow.</p>



<p class="wp-block-paragraph">Each setting solves a small problem.</p>



<h3 class="wp-block-heading">Keeping Sequence Objects Stable</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">frozen=True</pre></div>



<p class="wp-block-paragraph">means that once we create a sequence object, we cannot simply replace one of its fields later.</p>



<p class="wp-block-paragraph">Without it, code could potentially do something like:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence.sequence = &quot;AAAA&quot;</pre></div>



<p class="wp-block-paragraph">halfway through an analysis.</p>



<p class="wp-block-paragraph">With <code>frozen=True</code>, the model prevents that change. This is especially important in scientific workflows, where the same sequence may pass through many steps and algorithms. Unless we deliberately create a new sequence, we want to be sure that nothing accidentally changes the original data halfway through an analysis.</p>



<h3 class="wp-block-heading">Rejecting Unexpected Fields</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">extra=&quot;forbid&quot;</pre></div>



<p class="wp-block-paragraph">means that Pydantic will reject fields our model does not know about.</p>



<p class="wp-block-paragraph">For example, if we accidentally misspell:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">identifier</pre></div>



<p class="wp-block-paragraph">as:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">identifer</pre></div>



<p class="wp-block-paragraph">Pydantic will report the mistake instead of silently accepting an unexpected field.</p>



<h3 class="wp-block-heading">Cleaning Surrounding Whitespace</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">str_strip_whitespace=True</pre></div>



<p class="wp-block-paragraph">removes whitespace from the beginning and end of our string fields.</p>



<p class="wp-block-paragraph">For example:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">&quot;  sample_1  &quot;</pre></div>



<p class="wp-block-paragraph">becomes:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">sample_1</pre></div>



<p class="wp-block-paragraph">This gives us cleaner values without having to call <code>.strip()</code> manually every time we create a model.</p>



<h2 class="wp-block-heading">Adding Our Sequence Data</h2>



<p class="wp-block-paragraph">Now our model needs some actual biological sequence data.</p>



<p class="wp-block-paragraph">First, update the Pydantic import so we can use <code>Field</code>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from pydantic import BaseModel, ConfigDict, Field</pre></div>



<p class="wp-block-paragraph">Then add three fields inside <code>Sequence</code>:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">identifier: str = Field(min_length=1)
description: str | None = None
sequence: str = Field(min_length=1)</pre></div>



<p class="wp-block-paragraph">Our class now knows about:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">identifier
description
sequence</pre></div>



<p class="wp-block-paragraph">The <code>identifier</code> gives the sequence a name we can use in our workflow.</p>



<p class="wp-block-paragraph">The <code>description</code> is optional:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">description: str | None = None</pre></div>



<p class="wp-block-paragraph">because a manually created sequence may not always need one.</p>



<p class="wp-block-paragraph">And:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence: str</pre></div>



<p class="wp-block-paragraph">stores the actual biological symbols.</p>



<p class="wp-block-paragraph">For the identifier and sequence, we also use:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Field(min_length=1)</pre></div>



<p class="wp-block-paragraph">so an empty identifier or empty sequence is rejected immediately.</p>



<h2 class="wp-block-heading">A Quick Check in <code>application.py</code></h2>



<p class="wp-block-paragraph">We already have a working <code>application.py</code>, so let us use it as our checkpoint instead of creating a separate test program.</p>



<p class="wp-block-paragraph">Add this import:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.sequence.base import Sequence</pre></div>



<p class="wp-block-paragraph">Then replace our original sequence string:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">seq = &quot;AATTTTAAAAC&quot;</pre></div>



<p class="wp-block-paragraph">with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">bio_sequence = Sequence(
    identifier=&quot;example_sequence&quot;,
    description=&quot;Part 4.3 demonstration sequence&quot;,
    sequence=&quot;AATTTTAAAAC&quot;,
)

seq = bio_sequence.sequence</pre></div>



<p class="wp-block-paragraph">Everything else in our Part 4.2 application can stay exactly the same.</p>



<p class="wp-block-paragraph">Run:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Shell&quot;,&quot;language&quot;:&quot;Shell&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;shell&quot;}">uv run python application.py</pre></div>



<p class="wp-block-paragraph">Our k-mer results should still be:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">So even our basic <code>Sequence</code> model can already sit in front of the existing algorithms without changing their calculations.</p>



<p class="wp-block-paragraph">Now we can make this model nicer to work with.</p>



<h2 class="wp-block-heading">Adding Simple Sequence Behavior</h2>



<p class="wp-block-paragraph">We will add three small Python dunder methods so our <code>Sequence</code> model behaves more like the sequence string it contains. Most Python developers will already recognize these, so we only need to look at what each one gives us.</p>



<h3 class="wp-block-heading"><code>__len__()</code></h3>



<p class="wp-block-paragraph">Without it, we would write:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">len(bio_sequence.sequence)</pre></div>



<p class="wp-block-paragraph">With <code>__len__()</code>, we can simply write:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">len(bio_sequence)</pre></div>



<p class="wp-block-paragraph">Add:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">def __len__(self) -&gt; int:
    &quot;&quot;&quot;Return the number of symbols in the sequence.&quot;&quot;&quot;
    return len(self.sequence)</pre></div>



<p class="wp-block-paragraph">This lets the <code>Sequence</code> object report the length of the biological sequence it contains.</p>



<h3 class="wp-block-heading"><code>__getitem__()</code></h3>



<p class="wp-block-paragraph">Without it, indexing and slicing would look like:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">bio_sequence.sequence[0]
bio_sequence.sequence[:4]</pre></div>



<p class="wp-block-paragraph">With <code>__getitem__()</code>, we can use the model directly:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">bio_sequence[0]
bio_sequence[:4]</pre></div>



<p class="wp-block-paragraph">Add:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">def __getitem__(self, index: int | slice) -&gt; str:
    &quot;&quot;&quot;Return one symbol or a sequence slice.&quot;&quot;&quot;
    return self.sequence[index]</pre></div>



<p class="wp-block-paragraph">This gives us normal Python indexing and slicing without reaching into <code>.sequence</code> every time.</p>



<h3 class="wp-block-heading"><code>__iter__()</code></h3>



<p class="wp-block-paragraph">For iteration, we would normally write:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">for symbol in bio_sequence.sequence:</pre></div>



<p class="wp-block-paragraph">With <code>__iter__()</code>, we can write:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">for symbol in bio_sequence:</pre></div>



<p class="wp-block-paragraph">This is the first point where we need <code>Iterator</code>, so add:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from collections.abc import Iterator</pre></div>



<p class="wp-block-paragraph">Then add:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">def __iter__(self) -&gt; Iterator[str]:
    &quot;&quot;&quot;Iterate over sequence symbols.&quot;&quot;&quot;
    return iter(self.sequence)</pre></div>



<p class="wp-block-paragraph">Now our model can be used directly anywhere we want to move through the sequence one symbol at a time.</p>



<p class="wp-block-paragraph">Our base model is now doing something useful before we have written a single DNA-specific rule.</p>



<p class="wp-block-paragraph">It gives us structured sequence data and lets us work naturally with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">len(sequence)
sequence[0]
sequence[:4]
for symbol in sequence</pre></div>



<p class="wp-block-paragraph">Now we are ready to teach Genome Toolkit what makes a sequence specifically <strong>DNA</strong>.</p>



<h2 class="wp-block-heading">Building the <code>DNA</code> Model</h2>



<p class="wp-block-paragraph">Create our second file:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">src/genome_toolkit/sequence/dna.py</pre></div>



<p class="wp-block-paragraph">Our project now has:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">sequence/
├── base.py
└── dna.py          ← NEW</pre></div>



<p class="wp-block-paragraph">The DNA model is much smaller, so we can look at it together:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">&quot;&quot;&quot;DNA-specific sequence validation.&quot;&quot;&quot;

from pydantic import field_validator

from .base import Sequence


DNA_ALPHABET = frozenset(&quot;ACGTN&quot;)


class DNA(Sequence):
    &quot;&quot;&quot;DNA sequence validated against the A, C, G, T, and N alphabet.&quot;&quot;&quot;

    @field_validator(&quot;sequence&quot;)
    @classmethod
    def validate_nucleotides(cls, value: str) -&gt; str:
        &quot;&quot;&quot;Normalize DNA to uppercase and reject unsupported symbols.&quot;&quot;&quot;
        normalized = value.upper()
        invalid = set(normalized) - DNA_ALPHABET

        if invalid:
            symbols = &quot;, &quot;.join(sorted(invalid))
            raise ValueError(
                f&quot;Sequence contains invalid DNA symbols: {symbols}. &quot;
                &quot;Allowed symbols are A, C, G, T, and N.&quot;
            )

        return normalized</pre></div>



<h3 class="wp-block-heading">Inheriting Everything From <code>Sequence</code></h3>



<p class="wp-block-paragraph">The first important line is:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">class DNA(Sequence):</pre></div>



<p class="wp-block-paragraph">This means <code>DNA</code> inherits everything we already built in our base <code>Sequence</code> model. We do not need to redefine the identifier, description, sequence field, model configuration, length, indexing, slicing, or iteration again.</p>



<p class="wp-block-paragraph">So every <code>DNA</code> object already has:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">identifier
description
sequence
frozen model configuration
extra-field checks
whitespace stripping
length
indexing
slicing
iteration</pre></div>



<p class="wp-block-paragraph"><code>DNA</code> only adds the rule that is specific to DNA: which nucleotide symbols are allowed.</p>



<h3 class="wp-block-heading">Defining Our DNA Alphabet</h3>



<p class="wp-block-paragraph">We start with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">DNA_ALPHABET = frozenset(&quot;ACGTN&quot;)</pre></div>



<p class="wp-block-paragraph">A <code>frozenset</code> is simply a Python <code>set</code> that cannot be changed after it is created. That makes it a good fit for our DNA alphabet because these allowed symbols should stay fixed while Genome Toolkit is running.</p>



<p class="wp-block-paragraph">For this introductory DNA model, we support:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">A
C
G
T
N</pre></div>



<p class="wp-block-paragraph"><code>N</code> represents an unknown or unresolved nucleotide and appears commonly in real biological sequence data.</p>



<p class="wp-block-paragraph">Keeping the alphabet in one constant also means we have one clear place to expand the rule later if Genome Toolkit needs additional IUPAC symbols.</p>



<h3 class="wp-block-heading">Connecting Validation to the <code>sequence</code> Field</h3>



<p class="wp-block-paragraph">This line:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">@field_validator(&quot;sequence&quot;)</pre></div>



<p class="wp-block-paragraph">connects our validation function directly to the inherited <code>sequence</code> field.</p>



<p class="wp-block-paragraph">We do not call <code>validate_nucleotides()</code> ourselves. When we create:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">dna = DNA(
    identifier=&quot;example&quot;,
    sequence=&quot;acgtn&quot;,
)</pre></div>



<p class="wp-block-paragraph">Pydantic automatically runs the checks from our inherited <code>Sequence</code> model and then runs this DNA-specific validator before the final object is created.</p>



<p class="wp-block-paragraph">The process is:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">DNA(...)
   ↓
Sequence fields and model rules are checked
   ↓
validate_nucleotides() runs for sequence
   ↓
sequence is converted to uppercase
   ↓
DNA symbols are checked
   ↓
invalid symbols? → stop with validation error
   ↓
valid sequence? → return normalized sequence
   ↓
DNA object is created</pre></div>



<p class="wp-block-paragraph">So if the sequence is invalid, we never get a successfully created <code>DNA</code> object. The bad data is stopped before we can pass it deeper into Genome Toolkit.</p>



<h3 class="wp-block-heading">Why <code>@classmethod</code>?</h3>



<p class="wp-block-paragraph">Right under the field validator we use:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">@classmethod</pre></div>



<p class="wp-block-paragraph">Normally, a method inside a class works with an object that has already been created. For example, we first create:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">dna = DNA(...)</pre></div>



<p class="wp-block-paragraph">and only then call methods on <code>dna</code>.</p>



<p class="wp-block-paragraph">Our validator has to work earlier than that. It needs to check the sequence <strong>before</strong> Pydantic finishes creating the <code>DNA</code> object.</p>



<p class="wp-block-paragraph">That is why we use:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">@classmethod</pre></div>



<p class="wp-block-paragraph">It lets Pydantic call the validation function through the <code>DNA</code> class itself, without needing an already-created <code>dna</code> object first.</p>



<p class="wp-block-paragraph">Without it, a normal method would expect an existing object to work with, but at this point the object is still being created. So <code>@classmethod</code> solves a simple timing problem: <strong>validate first, create the final <code>DNA</code> object only if the data is valid.</strong></p>



<h3 class="wp-block-heading">Normalizing the Sequence</h3>



<p class="wp-block-paragraph">The validator receives the supplied sequence as:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">value</pre></div>



<p class="wp-block-paragraph">Then:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">normalized = value.upper()</pre></div>



<p class="wp-block-paragraph">converts lowercase DNA such as:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">acgtn</pre></div>



<p class="wp-block-paragraph">into:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">ACGTN</pre></div>



<p class="wp-block-paragraph">This means the rest of Genome Toolkit can work with one consistent uppercase representation.</p>



<h3 class="wp-block-heading">Finding Invalid Symbols With <code>set()</code></h3>



<p class="wp-block-paragraph">Next we have:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">invalid = set(normalized) - DNA_ALPHABET</pre></div>



<p class="wp-block-paragraph">A Python <code>set</code> keeps only unique values.</p>



<p class="wp-block-paragraph">For example, if:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">value = &quot;AATTTTZAAAC&quot;</pre></div>



<p class="wp-block-paragraph">then:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">normalized = value.upper()</pre></div>



<p class="wp-block-paragraph">is still:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">AATTTTZAAAC</pre></div>



<p class="wp-block-paragraph">and:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">set(normalized)</pre></div>



<p class="wp-block-paragraph">contains only the unique symbols:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">A, T, Z, C</pre></div>



<p class="wp-block-paragraph">The order of values inside a set does not matter.</p>



<p class="wp-block-paragraph">We then subtract our allowed DNA alphabet:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">{A, T, Z, C}
-
{A, C, G, T, N}
=
{Z}</pre></div>



<p class="wp-block-paragraph">So anything left in:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">invalid</pre></div>



<p class="wp-block-paragraph">is a symbol our DNA model does not support.</p>



<p class="wp-block-paragraph">For a valid sequence such as:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">AATTTTAAAAC</pre></div>



<p class="wp-block-paragraph">the unique symbols are only:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">A, T, C</pre></div>



<p class="wp-block-paragraph">and after subtracting the allowed alphabet, nothing is left.</p>



<h3 class="wp-block-heading">Stopping Invalid DNA</h3>



<p class="wp-block-paragraph">If <code>invalid</code> contains anything, we create a readable list of those symbols:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">symbols = &quot;, &quot;.join(sorted(invalid))</pre></div>



<p class="wp-block-paragraph">and raise:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">ValueError(...)</pre></div>



<p class="wp-block-paragraph">For:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">ACGTZ</pre></div>



<p class="wp-block-paragraph">the useful part of the error tells us:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Sequence contains invalid DNA symbols: Z.
Allowed symbols are A, C, G, T, and N.</pre></div>



<p class="wp-block-paragraph">If no invalid symbols are found, we finish with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">return normalized</pre></div>



<p class="wp-block-paragraph">That returned value becomes the final value stored inside:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">dna.sequence</pre></div>



<p class="wp-block-paragraph">So:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">&quot;aCgTn&quot;
    ↓
DNA(...)
    ↓
validation
    ↓
&quot;ACGTN&quot;
    ↓
fully created DNA object</pre></div>



<p class="wp-block-paragraph">while:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">&quot;ACGTZ&quot;
    ↓
DNA(...)
    ↓
validation
    ↓
error
    ↓
no DNA object is created</pre></div>



<p class="wp-block-paragraph">At this point, our general <code>Sequence</code> model gives us the common sequence behavior, while <code>DNA</code> adds exactly the biological rule we need for DNA.</p>



<h2 class="wp-block-heading">Exposing Our Sequence API</h2>



<p class="wp-block-paragraph">We now have the two models, but we do not want users of Genome Toolkit to depend on the internal filenames.</p>



<p class="wp-block-paragraph">Open:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">src/genome_toolkit/sequence/__init__.py</pre></div>



<p class="wp-block-paragraph">Add:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">&quot;&quot;&quot;Validated biological sequence models.&quot;&quot;&quot;

from .base import Sequence
from .dna import DNA

__all__ = [&quot;Sequence&quot;, &quot;DNA&quot;]</pre></div>



<p class="wp-block-paragraph">Now we can use the clean import:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.sequence import DNA</pre></div>



<p class="wp-block-paragraph">instead of:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.sequence.dna import DNA</pre></div>



<p class="wp-block-paragraph">This is the same idea we already used for our algorithms in Part 4.2.</p>



<p class="wp-block-paragraph">Our package exposes a clean public entry point while the internal files remain organized by responsibility.</p>



<h2 class="wp-block-heading">Expanding Our Existing <code>application.py</code></h2>



<p class="wp-block-paragraph">Now that the <code>DNA</code> model exists, we do not need a separate test program or a separate Python session.</p>



<p class="wp-block-paragraph">We already have a working <code>application.py</code> from Part 4.2, so we can use that same application to demonstrate every new feature we have just added.</p>



<p class="wp-block-paragraph">Our current application starts with:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.algorithms import (
    count_kmer,
    find_most_frequent_kmers,
)

seq = &quot;AATTTTAAAAC&quot;</pre></div>



<p class="wp-block-paragraph">The first change is one new import:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.sequence import DNA</pre></div>



<p class="wp-block-paragraph">Then instead of creating an arbitrary sequence string directly, we create a validated DNA object:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">dna = DNA(
    identifier=&quot;example_dna&quot;,
    description=&quot;Part 4.3 demonstration sequence&quot;,
    sequence=&quot;aattttaaaac&quot;,
)

seq = dna.sequence</pre></div>



<p class="wp-block-paragraph">Notice that we deliberately supplied the sequence in lowercase:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">aattttaaaac</pre></div>



<p class="wp-block-paragraph">Our DNA validator will normalize it to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">AATTTTAAAAC</pre></div>



<p class="wp-block-paragraph">The rest of our Part 4.2 application can stay exactly where it was. We simply add a few lines before the k-mer output so we can see what our new biological model can do.</p>



<p class="wp-block-paragraph">Update <code>application.py</code> to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">from genome_toolkit.algorithms import (
    count_kmer,
    find_most_frequent_kmers,
)
from genome_toolkit.sequence import DNA

dna = DNA(
    identifier=&quot;example_dna&quot;,
    description=&quot;Part 4.3 demonstration sequence&quot;,
    sequence=&quot;aattttaaaac&quot;,
)

seq = dna.sequence
kmer = &quot;AA&quot;
k_len = 3


print(f&quot;Identifier: {dna.identifier}&quot;)
print(f&quot;Description: {dna.description}&quot;)
print(f&quot;Validated sequence: {dna.sequence}&quot;)
print(f&quot;Sequence length: {len(dna)}&quot;)
print(f&quot;First nucleotide: {dna[0]}&quot;)
print(f&quot;First four nucleotides: {dna[:4]}&quot;)
print(f&quot;Nucleotides: {' '.join(dna)}&quot;)

print(&quot;DNA as JSON:&quot;)
print(dna.model_dump_json(indent=2))

print()

print(f&quot;Sequence: {seq}&quot;)
print(f&quot;k-mer: {kmer}&quot;)
print(f&quot;Repeats found: {count_kmer(seq, kmer)}&quot;)
print(f&quot;Most frequent k-mer: {find_most_frequent_kmers(seq, k_len)}&quot;)</pre></div>



<p class="wp-block-paragraph">This is still our Part 4.2 application, but now it also demonstrates the new biological model we added in Part 4.3.</p>



<p class="wp-block-paragraph">The first group of output shows that our DNA object now gives us:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">identifier
description
validated sequence
sequence length
indexing
slicing
iteration
JSON serialization</pre></div>



<p class="wp-block-paragraph">And the second group is still our original k-mer workflow.</p>



<p class="wp-block-paragraph">The important connection is this line:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">seq = dna.sequence</pre></div>



<p class="wp-block-paragraph">Our algorithms still receive a normal Python string, so we do not need to change them yet.</p>



<p class="wp-block-paragraph">What changed is that the string now comes from a successfully validated <code>DNA</code> object:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">raw sequence
      ↓
DNA(...)
      ↓
validated dna.sequence
      ↓
existing k-mer algorithms</pre></div>



<h2 class="wp-block-heading">Demonstrating Invalid DNA</h2>



<p class="wp-block-paragraph">Now let us deliberately break the sequence for a moment.</p>



<p class="wp-block-paragraph">Change only this line:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence=&quot;aattttaaaac&quot;,</pre></div>



<p class="wp-block-paragraph">to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence=&quot;aattttaaaaz&quot;,</pre></div>



<p class="wp-block-paragraph">Then run:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Shell&quot;,&quot;language&quot;:&quot;Shell&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;shell&quot;}">uv run python application.py</pre></div>



<p class="wp-block-paragraph">The application should stop when it tries to create the <code>DNA</code> object.</p>



<p class="wp-block-paragraph">Our validator sees:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Z</pre></div>



<p class="wp-block-paragraph">and rejects it because our current DNA alphabet only allows:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">A, C, G, T, N</pre></div>



<p class="wp-block-paragraph">The useful part of the validation error will tell us that the sequence contains an invalid DNA symbol:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Sequence contains invalid DNA symbols: Z.
Allowed symbols are A, C, G, T, and N.</pre></div>



<p class="wp-block-paragraph">Notice what happens here: our k-mer algorithms never run.</p>



<p class="wp-block-paragraph">That is exactly the protection we wanted. Invalid biological data is stopped before it reaches the scientific calculation.</p>



<p class="wp-block-paragraph">Now fix the sequence again:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence=&quot;aattttaaaac&quot;,</pre></div>



<p class="wp-block-paragraph">Our application is fully functional again.</p>



<h2 class="wp-block-heading">Running the Complete Part 4.3 Application</h2>



<p class="wp-block-paragraph">Run:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Shell&quot;,&quot;language&quot;:&quot;Shell&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;shell&quot;}">uv run python application.py</pre></div>



<p class="wp-block-paragraph">We should now see output similar to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Identifier: example_dna
Description: Part 4.3 demonstration sequence
Validated sequence: AATTTTAAAAC
Sequence length: 11
First nucleotide: A
First four nucleotides: AATT
Nucleotides: A A T T T T A A A A C
DNA as JSON:
{
  &quot;identifier&quot;: &quot;example_dna&quot;,
  &quot;description&quot;: &quot;Part 4.3 demonstration sequence&quot;,
  &quot;sequence&quot;: &quot;AATTTTAAAAC&quot;
}

Sequence: AATTTTAAAAC
k-mer: AA
Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">This is a much more useful checkpoint than running a separate temporary test.</p>



<p class="wp-block-paragraph">Our single <code>application.py</code> now demonstrates both generations of Genome Toolkit together:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Part 4.2
existing k-mer algorithms
        +
Part 4.3
validated biological DNA</pre></div>



<p class="wp-block-paragraph">The original scientific calculations are still unchanged:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">But now we know that the sequence reaching those calculations has already been normalized and checked against our DNA rules. We also carry useful information such as its identifier and description together with the sequence.</p>



<p class="wp-block-paragraph">Genome Toolkit can now:</p>



<ul class="wp-block-list">
<li>keep an identifier and optional description with the sequence;</li>



<li>normalize lowercase DNA to uppercase;</li>



<li>reject unsupported DNA symbols;</li>



<li>report sequence length;</li>



<li>support normal indexing, slicing, and iteration;</li>



<li>serialize the model to JSON;</li>



<li>pass the validated sequence directly into our existing algorithms.</li>
</ul>



<p class="wp-block-paragraph">So our workflow has grown from:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">string
   ↓
algorithm</pre></div>



<p class="wp-block-paragraph">to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">raw string
    ↓
validated DNA object
    ↓
dna.sequence
    ↓
existing algorithm</pre></div>



<p class="wp-block-paragraph">And we achieved that without rewriting the working k-mer code from Part 4.2.</p>



<h2 class="wp-block-heading">Our New Project Structure</h2>



<p class="wp-block-paragraph">At the end of Part 4.3, our project looks like this:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">genome_toolkit/
├── .git/
├── .gitignore
├── .venv/
├── README.md
├── application.py              # &lt;-- UPDATED
├── pyproject.toml              # &lt;-- UPDATED
├── uv.lock                     # &lt;-- UPDATED
└── src/
    └── genome_toolkit/
        ├── __init__.py
        ├── py.typed
        ├── algorithms/
        │   ├── __init__.py
        │   └── kmer.py
        └── sequence/            # &lt;-- NEW
            ├── __init__.py      # &lt;-- NEW
            ├── base.py          # &lt;-- NEW
            └── dna.py           # &lt;-- NEW</pre></div>



<p class="wp-block-paragraph">The responsibilities are now very clear:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">algorithms/
    scientific calculations

sequence/base.py
    shared biological sequence structure

sequence/dna.py
    DNA normalization and validation

sequence/__init__.py
    public sequence imports

application.py
    demonstrates how the pieces work together</pre></div>



<p class="wp-block-paragraph">And the most important thing is that this is still the same working Genome Toolkit we started with.</p>



<p class="wp-block-paragraph">We have simply added one new capability.</p>



<h2 class="wp-block-heading">Why We Keep File Loading Out of <code>DNA</code></h2>



<p class="wp-block-paragraph">We are still manually typing:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence=&quot;AATTTTAAAAC&quot;</pre></div>



<p class="wp-block-paragraph">That is intentional.</p>



<p class="wp-block-paragraph">It may be tempting to immediately add something like:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">DNA.from_fasta(&quot;sample.fasta&quot;)</pre></div>



<p class="wp-block-paragraph">But that would make the DNA model responsible for two different things:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">understanding DNA
+
understanding FASTA files</pre></div>



<p class="wp-block-paragraph">Those are separate problems.</p>



<p class="wp-block-paragraph">We want our DNA model to answer:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Is this valid DNA?</p>
</blockquote>



<p class="wp-block-paragraph">A loader should answer:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">How do I read sequence data from this source?</p>
</blockquote>



<p class="wp-block-paragraph">Keeping those responsibilities separate means the same DNA model can later validate data that came from:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">plain-text file
FASTA file
database
API
manual input</pre></div>



<p class="wp-block-paragraph">without changing the DNA class every time we add a new source.</p>



<p class="wp-block-paragraph">That is exactly where we are going next.</p>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">In Part 4.3, we added Genome Toolkit&#8217;s first validated biological models without changing our existing algorithms.</p>



<p class="wp-block-paragraph">We added Pydantic, created the new <code>sequence/</code> package, built a reusable <code>Sequence</code> base model, and created a <code>DNA</code> model that normalizes sequences to uppercase and rejects unsupported DNA symbols.</p>



<p class="wp-block-paragraph">We then expanded our existing <code>application.py</code> so the same program demonstrates the new DNA features and still runs the original k-mer workflow. We deliberately supplied an invalid DNA symbol, watched validation stop the application before the algorithms could run, fixed the sequence, and finished with one fully functional application that combines Part 4.2 and Part 4.3.</p>



<p class="wp-block-paragraph">Our project has therefore grown from:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">string → algorithm</pre></div>



<p class="wp-block-paragraph">to:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">string → validated DNA → algorithm</pre></div>



<p class="wp-block-paragraph">without breaking the working code we already had.</p>



<h3 class="wp-block-heading">New Concepts We Learned</h3>



<ul class="wp-block-list">
<li><strong>Pydantic</strong> — A Python validation library that gives us reusable model infrastructure such as field validation, useful errors, serialization, and schema information. We use it so Genome Toolkit can focus on biological rules instead of repeatedly rebuilding generic validation code.</li>
</ul>



<ul class="wp-block-list">
<li><strong><code>BaseModel</code></strong> — The Pydantic class our <code>Sequence</code> model inherits from. It turns our typed model fields into validated data when an object is created.</li>
</ul>



<ul class="wp-block-list">
<li><strong><code>Field(min_length=1)</code></strong> — Adds a rule to a model field. We use it to prevent empty identifiers and empty biological sequences from successfully entering our workflow.</li>
</ul>



<ul class="wp-block-list">
<li><strong><code>ConfigDict</code></strong> — Lets us configure shared model behavior. In <code>Sequence</code>, we use it to strip surrounding whitespace, reject unexpected fields, and prevent model fields from being reassigned after creation.</li>
</ul>



<ul class="wp-block-list">
<li><strong><code>field_validator</code></strong> — Lets us attach our own rule to a specific model field. We use it in <code>DNA</code> to normalize the sequence to uppercase and reject symbols outside our supported DNA alphabet.</li>
</ul>



<ul class="wp-block-list">
<li><strong>Validation boundary</strong> — The point where raw data becomes trusted biological data. Instead of asking every algorithm to validate DNA independently, we validate once when creating <code>DNA</code>.</li>
</ul>



<ul class="wp-block-list">
<li><strong>Base model and specialized model</strong> — <code>Sequence</code> contains behavior shared by biological sequences, while <code>DNA</code> adds the rules that are specific to DNA. This gives us a natural place to add RNA or protein models later without duplicating all of the common sequence behavior.</li>
</ul>



<h2 class="wp-block-heading">What is Next?</h2>



<p class="wp-block-paragraph">Our DNA model now knows whether a sequence is biologically valid, but we are still typing that sequence directly into Python:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text/x-python&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence=&quot;AATTTTAAAAC&quot;</pre></div>



<p class="wp-block-paragraph">Real biological data usually comes from somewhere else.</p>



<p class="wp-block-paragraph">In Part 4.4, we will add our first simple loading layer and read sequence data from a plain-text file.</p>



<p class="wp-block-paragraph">The new workflow will become:</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;showPanel&quot;:false,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;textile&quot;,&quot;mime&quot;:&quot;text/x-textile&quot;,&quot;theme&quot;:&quot;monokai&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;Textile&quot;,&quot;language&quot;:&quot;Textile&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;textile&quot;}">plain-text file
      ↓
loaded sequence data
      ↓
DNA(...)
      ↓
validated DNA
      ↓
our existing Genome Toolkit</pre></div>



<p class="wp-block-paragraph">We will keep the same approach we used here: add one meaningful piece, test it immediately, and then connect it to the working project.</p>



<p class="wp-block-paragraph">The full source code for Genome Toolkit is available here:</p>



<p class="wp-block-paragraph"><a href="https://github.com/rebelC0der/Genome_Toolkit">https://github.com/rebelC0der/Genome_Toolkit</a></p>



<p class="wp-block-paragraph">I hope adding our first validated biological sequence models and teaching Genome Toolkit what valid DNA looks like was useful for your bioinformatics and programming journey! If you found this article valuable and want to help us continue building rebelScience, please consider supporting our project. You can explore various ways to contribute here:</p>



<p class="wp-block-paragraph"><a href="https://rebelscience.club/cryptocurrency-donations/">https://rebelscience.club/cryptocurrency-donations/</a></p>



<p class="wp-block-paragraph">Until next time, rebelCoder, signing out.</p>



<p class="wp-block-paragraph">Video version can be found here:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Genome Toolkit. Part 4.3: Building Validated Biological Models" width="640" height="360" src="https://www.youtube.com/embed/MNv6O4NoSvE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>
]]></content:encoded></item></channel></rss>