<?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.2: Modernizing the Existing Python Project</title><link>https://rebelscience.club/2026/08/genome-toolkit-part-4-2-modernizing-the-existing-python-project/</link><guid isPermaLink="true">https://rebelscience.club/2026/08/genome-toolkit-part-4-2-modernizing-the-existing-python-project/</guid><pubDate>Fri, 28 Aug 2026 14:08:44 GMT</pubDate><description>In Part 4.2, we modernize Genome Toolkit and turn our original project into a proper installable Python package. We move from Pipenv to uv, organize the code under src/, move our existing k-mer algorithms into the new package, and update application.py to use them. Most importantly, we keep the scientific calculations unchanged and verify that Genome Toolkit still produces exactly the same results.
</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.1, we looked at where Genome Toolkit is going and why it makes sense to turn our small educational project into a proper scientific Python package. Now we are finally going to start doing it.</p>



<p class="wp-block-paragraph">The important thing is that our scientific calculations already work. We have two k-mer algorithms, we know what input they receive, and we know exactly what output our current application produces. So before we change anything, we are going to use that working application as our reference point.</p>



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



<p class="wp-block-paragraph">We are continuing inside the same Genome Toolkit Git repository:</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;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;}">genome_toolkit/
├── .git/
├── .gitignore
├── application.py
├── genome_toolkit.py
├── Pipfile
└── Pipfile.lock</pre></div>



<p class="wp-block-paragraph">The <code>.git/</code> directory is important because it contains the history of our project. We are improving the same Genome Toolkit we have already been building, so we keep that history and continue working in the same repository.</p>



<p class="wp-block-paragraph">Before touching the structure, let us run the original application one more time:</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;}">python application.py</pre></div>



<p class="wp-block-paragraph">Or, if you are using the Code Runner extension in Visual Studio Code, you can run it 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Ctrl + Alt + N</pre></div>



<p class="wp-block-paragraph">We should get:</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;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: AATTTTAAAAC
k-mer: AA
Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">This output is our <strong>working checkpoint</strong>. We already know these calculations are correct for the example we have been using throughout the series, so after we reorganize the project, we will run the application again and compare the result with this exact output.</p>



<p class="wp-block-paragraph">That gives us a very simple goal for this article:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">old project structure
        ↓
modern Python package
        ↓
same scientific calculations</pre></div>



<p class="wp-block-paragraph">We are changing how Genome Toolkit is organized, not what our k-mer algorithms calculate.</p>



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



<p class="wp-block-paragraph">Right now, Genome Toolkit is still a very small Python project. We have our environment managed with Pipenv, our scientific code lives in one <code>genome_toolkit.py</code> file, and we create a <code>genomeToolkit</code> object before calling our algorithms.</p>



<p class="wp-block-paragraph">That worked perfectly for the first few parts of the series, but now we want to give Genome Toolkit a cleaner structure that will be easier to grow.</p>



<p class="wp-block-paragraph">By the end of this article, we will have:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">uv
        ↓
a modern Python project

src/genome_toolkit/
        ↓
our installable Genome Toolkit package

algorithms/
        ↓
our k-mer functions</pre></div>



<p class="wp-block-paragraph">We are not going to learn all of Python packaging at once. We will change one small thing at a time, explain why it helps, and keep checking that our original scientific calculations still work.</p>



<p class="wp-block-paragraph">The first thing we are going to modernize is how we manage the Python project itself.</p>



<h2 class="wp-block-heading">Moving From Pipenv to uv</h2>



<p class="wp-block-paragraph">When we started Genome Toolkit, we used <strong>Pipenv</strong> to create a Python environment and manage our project dependencies. That is why our repository currently contains:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Pipfile
Pipfile.lock</pre></div>



<p class="wp-block-paragraph">For the modern version of Genome Toolkit, we are going to use <strong>uv</strong>.</p>



<p class="wp-block-paragraph"><code>uv</code> is a modern Python project and package manager. It can create projects, manage Python environments, install dependencies, generate lock files, build packages, and run Python commands for us.</p>



<p class="wp-block-paragraph">If <code>uv</code> is new to you, Corey Schafer has an excellent detailed tutorial on it. We are going to use only the parts we need for Genome Toolkit, but if you want a deeper introduction to the tool, I highly recommend watching his video:</p>



<p class="wp-block-paragraph"><strong><a href="https://youtu.be/AMdG7IjgSPM">Python Tutorial: UV &#8211; A Faster, All-in-One Package Manager to Replace Pip and Venv</a></strong></p>



<p class="wp-block-paragraph">In practical terms, many of the jobs for which we previously used several Python tools can now be handled through one tool:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">project setup
environment
dependencies
lock file
package build
running commands
        ↓
       uv</pre></div>



<p class="wp-block-paragraph">For Genome Toolkit, this gives us a clean modern starting point without adding unnecessary tools.</p>



<h3 class="wp-block-heading">Installing <code>uv</code></h3>



<p class="wp-block-paragraph">Before we start using <code>uv</code>, we first need to install it.</p>



<p class="wp-block-paragraph">On macOS and Linux, run:</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;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;}">curl -LsSf https://astral.sh/uv/install.sh | sh</pre></div>



<p class="wp-block-paragraph">On Windows, run:</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;powershell&quot;,&quot;mime&quot;:&quot;application/x-powershell&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;PowerShell&quot;,&quot;language&quot;:&quot;PowerShell&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;powershell&quot;}">powershell -ExecutionPolicy ByPass -c &quot;irm https://astral.sh/uv/install.ps1 | iex&quot;</pre></div>



<p class="wp-block-paragraph">That installs <code>uv</code> on our system so we can use commands 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">uv init
uv sync
uv run</pre></div>



<p class="wp-block-paragraph">If you already have <code>uv</code> installed, you can skip this step.</p>



<h3 class="wp-block-heading">Removing the Old Environment Files</h3>



<p class="wp-block-paragraph">We begin by removing the old Pipenv declarations:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">rm Pipfile Pipfile.lock</pre></div>



<p class="wp-block-paragraph">We are not deleting our Python code. <code>application.py</code> and <code>genome_toolkit.py</code> stay in place while we create the new package around them.</p>



<p class="wp-block-paragraph">Our existing <code>.gitignore</code> also needs a small update.</p>



<p class="wp-block-paragraph">Because this project already has its 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">.git/</pre></div>



<p class="wp-block-paragraph">Git repository, <code>uv</code> does not generate a new <code>.gitignore</code> for us. So instead of deleting the file, open the existing <code>.gitignore</code> and replace its contents 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;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;}"># Python-generated files

__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

# Virtual environments

.venv</pre></div>



<p class="wp-block-paragraph">This keeps temporary Python files, build files, and our local virtual environment out of the Git repository.</p>



<p class="wp-block-paragraph">We keep <code>.git/</code> exactly where it is because it contains the existing history of Genome Toolkit. At this point, the scientific code has not changed at all; we have only removed the old Pipenv configuration and updated the files that control our development environment.</p>



<h2 class="wp-block-heading">Initializing Genome Toolkit as a Library</h2>



<p class="wp-block-paragraph">Now we can initialize the existing directory as a <code>uv</code> library:</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;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 init --lib --name genome-toolkit</pre></div>



<p class="wp-block-paragraph">There are two useful parts in this command. <code>--name genome-toolkit</code> gives the project its package distribution name, while <code>--lib</code> tells <code>uv</code> that Genome Toolkit is a <strong>library</strong>: reusable Python code that other programs can import and use.</p>



<p class="wp-block-paragraph">That distinction is useful for our project:</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;}">library
provides reusable scientific functions and objects

application
uses those functions and decides what to show the user</pre></div>



<p class="wp-block-paragraph">Genome Toolkit itself is becoming the reusable library. Our existing <code>application.py</code> stays at the top level as a simple development and demonstration program that uses that library.</p>



<p class="wp-block-paragraph">After running the command, <code>uv</code> creates the modern project files and a <code>src/</code> package structure for us. The exact small details generated by <code>uv</code> can change between versions, so the important thing is to understand the structure rather than memorize every generated line.</p>



<p class="wp-block-paragraph">We should now see the beginning of a package layout 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">genome_toolkit/
├── .git/
├── .gitignore
├── application.py
├── genome_toolkit.py
├── pyproject.toml
├── README.md
└── src/
    └── genome_toolkit/
        ├── __init__.py
        └── py.typed</pre></div>



<p class="wp-block-paragraph">This is our first major improvement. We still have our original files at the repository root, but now we also have the place where our real installable <code>genome_toolkit</code> package will live:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/genome_toolkit/</pre></div>



<h2 class="wp-block-heading">What Is the <code>src/</code> Layout?</h2>



<p class="wp-block-paragraph">The new <code>src/</code> directory may look like an unnecessary extra folder at first. Why not simply put the package directly in the repository root?</p>



<p class="wp-block-paragraph">The basic idea is separation:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">repository files
        ↓
src/
        ↓
installable Python package</pre></div>



<p class="wp-block-paragraph">The repository contains things such as <code>README.md</code>, configuration files, tests, sample data, and our development application. The actual Python package that another project imports lives under <code>src/</code>.</p>



<p class="wp-block-paragraph">This gives us a clearer distinction between:</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;}">the project repository
and
the installed genome_toolkit package</pre></div>



<p class="wp-block-paragraph">Later, when we write:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">import genome_toolkit</pre></div>



<p class="wp-block-paragraph">we want Python to use the installed package under <code>src/</code>, not accidentally find some unrelated file at the repository root.</p>



<p class="wp-block-paragraph">We will see one very practical example of why that matters later in this article when we remove the old <code>genome_toolkit.py</code> file.</p>



<h2 class="wp-block-heading">The New <code>pyproject.toml</code></h2>



<p class="wp-block-paragraph">One of the most important files created by <code>uv</code> 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">pyproject.toml</pre></div>



<p class="wp-block-paragraph">This is the main configuration file for a modern Python project. Our old setup used <code>Pipfile</code> for environment and dependency information, while <code>pyproject.toml</code> gives us one standard place for the package information that Python tools need.</p>



<p class="wp-block-paragraph">For Genome Toolkit, we keep the structure generated by <code>uv</code> and set the project information we actually own:</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;}">[project]
name = &quot;genome-toolkit&quot;
version = &quot;0.1.0&quot;
description = &quot;A small, typed bioinformatics toolkit for validated sequences and structured analyses.&quot;
readme = &quot;README.md&quot;
requires-python = &quot;&gt;=3.12&quot;
dependencies = []</pre></div>



<p class="wp-block-paragraph">Let us go through this from top to bottom.</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;}">name = &quot;genome-toolkit&quot;</pre></div>



<p class="wp-block-paragraph">This is the package distribution name.</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;}">version = &quot;0.1.0&quot;</pre></div>



<p class="wp-block-paragraph">Genome Toolkit is still at the beginning of its development, so we keep our current <code>0.1.0</code> version.</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;}">description = &quot;A small, typed bioinformatics toolkit for validated sequences and structured analyses.&quot;</pre></div>



<p class="wp-block-paragraph">This gives package tools a short description of what the project 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;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;}">readme = &quot;README.md&quot;</pre></div>



<p class="wp-block-paragraph">This tells packaging tools which file contains the longer project description.</p>



<p class="wp-block-paragraph">Then 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;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;}">requires-python = &quot;&gt;=3.12&quot;</pre></div>



<p class="wp-block-paragraph">This tells users and package tools which Python versions Genome Toolkit supports. Notice that this does <strong>not</strong> say that every developer must use one exact Python 3.12 installation; it says that the package requires Python 3.12 or newer.</p>



<p class="wp-block-paragraph">Finally:</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 = []</pre></div>



<p class="wp-block-paragraph">At this point Genome Toolkit has no external runtime dependencies, so the list is empty. That will change soon, but we do not add dependencies before we actually need them.</p>



<h3 class="wp-block-heading">Removing the Local Python Version Pin</h3>



<p class="wp-block-paragraph">Depending on the current <code>uv</code> template, project initialization may also create:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">.python-version</pre></div>



<p class="wp-block-paragraph">That file can pin a local checkout to one particular development Python version.</p>



<p class="wp-block-paragraph">For Genome Toolkit, the compatibility rule we care about is already declared in <code>pyproject.toml</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;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;}">requires-python = &quot;&gt;=3.12&quot;</pre></div>



<p class="wp-block-paragraph">So if <code>.python-version</code> was generated, we remove it:</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;}">rm .python-version</pre></div>



<p class="wp-block-paragraph">This keeps the package rule simple: Python 3.12 or newer.</p>



<h2 class="wp-block-heading">How Does Genome Toolkit Become an Installable Package?</h2>



<p class="wp-block-paragraph">When we ran:</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;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 init --lib --name genome-toolkit</pre></div>



<p class="wp-block-paragraph"><code>uv</code> also added the small piece of configuration Python needs to turn our source code into an installable package.</p>



<p class="wp-block-paragraph">You will see it inside <code>pyproject.toml</code> under:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">[build-system]</pre></div>



<p class="wp-block-paragraph">We do not need to change it.</p>



<p class="wp-block-paragraph">For Genome Toolkit, our setup is very simple:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Python code
      ↓
uv
      ↓
installable genome_toolkit package</pre></div>



<p class="wp-block-paragraph">We are not compiling C or C++ code, creating special extensions, or doing anything unusual. Genome Toolkit is just a normal Python package, so the setup that <code>uv</code> generated for us already does the job.</p>



<p class="wp-block-paragraph">This is all we need to understand for now. Later, if our package ever needs a more complicated build process, we can learn about that when we actually need it.</p>



<h2 class="wp-block-heading">Moving Our Algorithms Into the Package</h2>



<p class="wp-block-paragraph">Now our package structure is ready, but both of our scientific algorithms are still sitting in the old root-level 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">genome_toolkit.py</pre></div>



<p class="wp-block-paragraph">There is no reason to recreate them one at a time. They already belong together, so we can simply move the existing file into our new package.</p>



<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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/genome_toolkit/</pre></div>



<p class="wp-block-paragraph">create a new folder called:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">algorithms</pre></div>



<p class="wp-block-paragraph">Then move:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">genome_toolkit.py</pre></div>



<p class="wp-block-paragraph">into that folder and rename 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">kmer.py</pre></div>



<p class="wp-block-paragraph">Finally, create an empty:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">__init__.py</pre></div>



<p class="wp-block-paragraph">inside the new <code>algorithms/</code> folder.</p>



<p class="wp-block-paragraph">We should now have:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/
└── genome_toolkit/
    └── algorithms/
        ├── __init__.py
        └── kmer.py</pre></div>



<p class="wp-block-paragraph">That already makes the purpose of the file much clearer:</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;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;}">genome_toolkit
      ↓
algorithms
      ↓
kmer.py
      ↓
our k-mer algorithms</pre></div>



<p class="wp-block-paragraph">Both of our existing algorithms have now moved into the new package together. We have not changed how they work yet; we have simply given them a better home.</p>



<h3 class="wp-block-heading">Simplifying <code>kmer.py</code></h3>



<p class="wp-block-paragraph">Our old file wrapped both algorithms inside the <code>genomeToolkit</code> class.</p>



<p class="wp-block-paragraph">Originally, the two methods begin like this:</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 count_kmer(self, sequence, kmer):</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;}">def find_most_frequent_kmers(self, sequence, k_len):</pre></div>



<p class="wp-block-paragraph">For Part 4.2, we are making only one small structural change to them: they become plain functions instead of class methods.</p>



<p class="wp-block-paragraph">We will also add type hints to the function signatures:</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 count_kmer(sequence: str, kmer: str) -&gt; int:</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;}">def find_most_frequent_kmers(
    sequence: str,
    k_len: int,
) -&gt; list[str]:</pre></div>



<p class="wp-block-paragraph">That means:</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;}">remove self
    +
add type hints</pre></div>



<p class="wp-block-paragraph">The actual algorithms stay exactly the same.</p>



<p class="wp-block-paragraph">Update <code>kmer.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;}">&quot;&quot;&quot;K-mer analysis algorithms.&quot;&quot;&quot;


def count_kmer(sequence: str, kmer: str) -&gt; int:
    &quot;&quot;&quot;
    Counts the number of times a specific k-mer appears in a given sequence,
    including overlapping k-mers.

    Parameters:
        sequence (str): The DNA sequence to search in.
        kmer (str): The specific k-mer to search for in the sequence.

    Returns:
        int: The number of times the k-mer appears in the sequence.
    &quot;&quot;&quot;
    kmer_count = 0

    for position in range(len(sequence) - (len(kmer) - 1)):
        if sequence[position : position + len(kmer)] == kmer:
            kmer_count += 1

    return kmer_count


def find_most_frequent_kmers(
    sequence: str,
    k_len: int,
) -&gt; list[str]:
    &quot;&quot;&quot;
    Finds the most frequent k-mers of a given length in a DNA string.

    Parameters:
        sequence (str): The DNA string to search.
        k_len (int): The length of the k-mers to search for.

    Returns:
        list: A list of the most frequent k-mers in the DNA string.
    &quot;&quot;&quot;
    kmer_frequencies = {}

    for i in range(len(sequence) - k_len + 1):
        kmer = sequence[i : i + k_len]
        if kmer in kmer_frequencies:
            kmer_frequencies[kmer] += 1
        else:
            kmer_frequencies[kmer] = 1

    highest_frequency = max(kmer_frequencies.values())

    return [
        kmer
        for kmer, frequency in kmer_frequencies.items()
        if frequency == highest_frequency
    ]</pre></div>



<p class="wp-block-paragraph">Notice what did <strong>not</strong> change:</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;}">kmer_count = 0
kmer_frequencies = {}
the loops
the comparisons
the counting logic
the return logic</pre></div>



<p class="wp-block-paragraph">We are not improving or modernizing the algorithms themselves in this part. We are moving the same calculations into a proper package and changing the way we call them.</p>



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



<p class="wp-block-paragraph">We now have:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">algorithms/
├── __init__.py
└── kmer.py</pre></div>



<p class="wp-block-paragraph">We could import directly from the <code>kmer.py</code> module:</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.kmer import count_kmer</pre></div>



<p class="wp-block-paragraph">That works, but we can give users a cleaner public entry point through:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/genome_toolkit/algorithms/__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;Bioinformatics algorithms.&quot;&quot;&quot;

from .kmer import count_kmer, find_most_frequent_kmers

__all__ = [&quot;count_kmer&quot;, &quot;find_most_frequent_kmers&quot;]</pre></div>



<p class="wp-block-paragraph">Now both algorithms can be imported from:</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,
)</pre></div>



<p class="wp-block-paragraph">This is the public algorithm interface we want to expose.</p>



<p class="wp-block-paragraph">The 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;}">from .kmer import count_kmer, find_most_frequent_kmers</pre></div>



<p class="wp-block-paragraph">re-exports the two functions from <code>kmer.py</code> through the <code>algorithms</code> package.</p>



<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;}">__all__ = [&quot;count_kmer&quot;, &quot;find_most_frequent_kmers&quot;]</pre></div>



<p class="wp-block-paragraph">makes our intention explicit: these are the names this package is deliberately exposing as its public API.</p>



<p class="wp-block-paragraph">For now, we only expose the two algorithms we actually have.</p>



<p class="wp-block-paragraph">That is enough to reconnect our application immediately and check whether the refactor still produces the exact same result.</p>



<h2 class="wp-block-heading">Updating <code>application.py</code></h2>



<p class="wp-block-paragraph">Our algorithms are now inside the new package, so the next step is to update <code>application.py</code> to use them.</p>



<p class="wp-block-paragraph">We only need to change the import, remove the old <code>gt</code> object, and update the two places where we call our algorithms:</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 (  # CHANGE TO
    count_kmer,
    find_most_frequent_kmers,
)


# gt = genomeToolkit()  # REMOVE

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;)  # UPDATED
print(
    &quot;Most frequent k-mer:&quot;,
    find_most_frequent_kmers(seq, k_len),  # UPDATED
)</pre></div>



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



<p class="wp-block-paragraph">We no longer import the old <code>genomeToolkit</code> class or create a <code>gt</code> object. Instead, we import our two functions directly from the new <code>algorithms</code> package and call them directly.</p>



<p class="wp-block-paragraph">Everything else stays exactly the same.</p>



<p class="wp-block-paragraph">Now we are ready to synchronize the new package and test it.</p>



<h2 class="wp-block-heading">Synchronizing and Testing the New Project</h2>



<p class="wp-block-paragraph">Now we want to test our changes immediately.</p>



<p class="wp-block-paragraph">Because Genome Toolkit is now an installable package under <code>src/</code>, we first synchronize the project environment, run this command from the project root:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">uv sync</pre></div>



<p class="wp-block-paragraph">The first time we run <code>uv sync</code>, <code>uv</code> creates our local virtual environment:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">.venv/</pre></div>



<p class="wp-block-paragraph">It also creates:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">uv.lock</pre></div>



<p class="wp-block-paragraph"><code>uv.lock</code> records the exact package versions used by the project so the same environment can be recreated consistently later.</p>



<p class="wp-block-paragraph"><code>uv sync</code> then installs our current Genome Toolkit package into the new <code>.venv</code> according to <code>pyproject.toml</code>.</p>



<p class="wp-block-paragraph">The first time this environment is created, VS Code or VSCodium may show a message like:</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;}">We noticed a new environment has been created.
Do you want to select it for the workspace folder?</pre></div>



<p class="wp-block-paragraph">Just select <strong>Yes</strong>.</p>



<p class="wp-block-paragraph">If the message does not appear, or the editor is still using another Python installation, check the Python interpreter shown in the bottom-right corner of VS Code/VSCodium and select our new project environment. It should point to the <code>.venv</code> created inside the Genome Toolkit project, usually shown as something 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">('.venv': venv)</pre></div>



<p class="wp-block-paragraph">After this step, both the editor and our project environment know where:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">genome_toolkit</pre></div>



<p class="wp-block-paragraph">actually lives, so our new import can work normally.</p>



<p class="wp-block-paragraph">If you use <code>uv run</code>, <code>uv</code> can also synchronize the environment automatically before running the command. We are running <code>uv sync</code> explicitly here because it gives us a clear checkpoint and also prepares the <code>.venv</code> environment for editors and Code Runner.</p>



<p class="wp-block-paragraph">Now for the important part.</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;:false,&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;:false,&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;}">uv run python application.py</pre></div>



<p class="wp-block-paragraph">We should see:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Sequence: AATTTTAAAAC
k-mer: AA
Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">The scientific output is exactly the same as before.</p>



<p class="wp-block-paragraph">That is the result we wanted. We changed the environment manager, package structure, imports, and the way our algorithms are exposed, and we also replaced a stateless class with plain functions.</p>



<p class="wp-block-paragraph">But <code>count_kmer()</code> still returns:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">4</pre></div>



<p class="wp-block-paragraph">and <code>find_most_frequent_kmers()</code> still returns:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">Perfect. This is the checkpoint we wanted: we moved the algorithms, simplified how we call them, reconnected <code>application.py</code>, and the scientific result is still exactly the same.</p>



<p class="wp-block-paragraph">Now that the important path works again, we can take care of two small package details before we finish.</p>



<h2 class="wp-block-heading">Keeping One Package Version</h2>



<p class="wp-block-paragraph">Now that our application works again, let us clean up one small package detail. The <code>uv</code> template also created:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/genome_toolkit/__init__.py</pre></div>



<p class="wp-block-paragraph">This is the top-level package initializer.</p>



<p class="wp-block-paragraph">We already declared our package version in <code>pyproject.toml</code>:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">version = &quot;0.1.0&quot;</pre></div>



<p class="wp-block-paragraph">We could write the same version again inside Python:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">__version__ = &quot;0.1.0&quot;</pre></div>



<p class="wp-block-paragraph">but then we would have two places to keep synchronized. Instead, we keep one source of truth, so replace the generated <code>src/genome_toolkit/__init__.py</code> 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;}">&quot;&quot;&quot;Genome Toolkit package.&quot;&quot;&quot;

from importlib.metadata import version

__version__ = version(&quot;genome-toolkit&quot;)

__all__ = [&quot;__version__&quot;]</pre></div>



<p class="wp-block-paragraph">The 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 importlib.metadata import version</pre></div>



<p class="wp-block-paragraph">comes from Python&#8217;s standard library. It lets our package read the version stored in the installed package metadata.</p>



<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;}">__version__ = version(&quot;genome-toolkit&quot;)</pre></div>



<p class="wp-block-paragraph">means Python can still tell us the Genome Toolkit version, but the actual version number remains declared in one place:</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
        ↓
installed package metadata
        ↓
genome_toolkit.__version__</pre></div>



<p class="wp-block-paragraph">That is easier to maintain than copying <code>"0.1.0"</code> into multiple files.</p>



<p class="wp-block-paragraph">This may look like a small packaging detail now, but the version number will become much more important once we start using Genome Toolkit for real biological experiments.</p>



<p class="wp-block-paragraph">Imagine that later we analyze a real genome and save the result. If Genome Toolkit changes over time, we will want to know exactly which version of the toolkit produced that result:</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 0.1.0
        ↓
biological data
        ↓
scientific analysis
        ↓
saved result</pre></div>



<p class="wp-block-paragraph">That version becomes part of the scientific context of the experiment. If we return to the same data months later, or somebody else wants to repeat our analysis, knowing which Genome Toolkit version was used helps us reproduce the same computational setup.</p>



<p class="wp-block-paragraph">This connects directly to two ideas we introduced in Part 4.1: <strong>reproducibility</strong> and <strong>provenance</strong>. We will come back to both in much more detail in the upcoming articles, when Genome Toolkit starts returning structured scientific results and we begin recording where those results came from.</p>



<p class="wp-block-paragraph">For now, the important thing is simple: Genome Toolkit should have one reliable version number, and every part of the package should read that same version.</p>



<h2 class="wp-block-heading">What Is <code>py.typed</code>? In Simple Terms</h2>



<p class="wp-block-paragraph">There is one more small file that <code>uv</code> created for us:</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;}">src/genome_toolkit/py.typed</pre></div>



<p class="wp-block-paragraph">The file is empty, and we leave it empty.</p>



<p class="wp-block-paragraph">So what does it actually do?</p>



<p class="wp-block-paragraph">In simple terms, <code>py.typed</code> is just a small <strong>marker file</strong>. It tells Python development tools:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Genome Toolkit includes type hints in its code, so you can use them.</p>
</blockquote>



<p class="wp-block-paragraph">For example, we now have functions 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;}">def count_kmer(sequence: str, kmer: str) -&gt; int:</pre></div>



<p class="wp-block-paragraph">The type hints tell us that:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">sequence → string
kmer     → string
result   → integer</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;}">def find_most_frequent_kmers(
    sequence: str,
    k_len: int,
) -&gt; list[str]:</pre></div>



<p class="wp-block-paragraph">tells us that the function expects a string and an integer, and returns a list of strings.</p>



<p class="wp-block-paragraph">The <code>py.typed</code> file simply tells compatible editors and type-checking tools that these type hints are intentionally part of Genome Toolkit.</p>



<p class="wp-block-paragraph">Without <code>py.typed</code>, another project may import Genome Toolkit and still run perfectly, but some type-checking tools may not automatically treat our package&#8217;s type hints as part of its public interface.</p>



<p class="wp-block-paragraph">With <code>py.typed</code>, we are explicitly telling those tools:</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 includes type information.
Please use it.</pre></div>



<p class="wp-block-paragraph">So if another developer passes the wrong kind of value to one of our functions, their editor or type checker has a better chance of warning them before the code even runs.</p>



<p class="wp-block-paragraph">We do not need to write anything inside <code>py.typed</code>. We just keep the empty file in the package.</p>



<h2 class="wp-block-heading">A Quick <code>README.md</code> Update</h2>



<p class="wp-block-paragraph">Before we finish the main part of Part 4.2, let us make one small but useful update 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">README.md</pre></div>



<p class="wp-block-paragraph"><code>uv</code> created this file when we initialized the project, and now we can add a few simple instructions so anyone who finds Genome Toolkit on GitHub knows how to run it after cloning the repository.</p>



<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;: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;}">```markdown
## Running Genome Toolkit

After cloning the repository, synchronize the project environment:

```bash
uv sync
```

Then run Genome Toolkit:

```bash
uv run application.py
```</pre></div>



<p class="wp-block-paragraph">That is enough for now.</p>



<p class="wp-block-paragraph">Anyone cloning the project can immediately see the two steps they need:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">clone repository
      ↓
uv sync
      ↓
uv run application.py</pre></div>



<p class="wp-block-paragraph">As Genome Toolkit grows, we can keep expanding the README with installation instructions, examples, supported biological data, and other useful project information. For now, we only add what a new user actually needs to run the project.</p>



<h2 class="wp-block-heading">Before We Finish Part 4.2</h2>



<p class="wp-block-paragraph">And that is it for the main part of Part 4.2. Genome Toolkit is now running as a modern Python package, our two original k-mer algorithms are still producing the same results, and we have a much better foundation for everything we are going to build next.</p>



<p class="wp-block-paragraph">Before we close this part, however, I want to introduce two optional Pro Tips that will help us a lot as Genome Toolkit grows. They are not required for the project, so you can skip them completely if you want, but they are also useful habits that can serve you well in your own Python projects.</p>



<p class="wp-block-paragraph">The first is for those of us who use the <strong>Code Runner</strong> extension. Because our project now uses <code>uv</code> and its own <code>.venv</code>, Code Runner may need a small configuration change so it runs our code inside the correct environment.</p>



<p class="wp-block-paragraph">The second is about <strong>Ruff</strong>, a modern Python linter and formatter. It can automatically keep our code clean and consistently formatted as the project grows.</p>



<p class="wp-block-paragraph">If you want to keep the setup minimal, feel free to skip both. If you want a smoother development workflow going forward, I recommend following them.</p>



<h2 class="wp-block-heading">Pro Tip #1: Code Runner With <code>uv</code></h2>



<p class="wp-block-paragraph">If you have been following rebelScience for a while, you may already use the <strong>Code Runner</strong> extension in VS Code or VSCodium to run Python files quickly without typing a terminal command every time.</p>



<p class="wp-block-paragraph">The default shortcuts are:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Linux / Windows: Ctrl + Alt + N
macOS:           Cmd + Option + N</pre></div>



<p class="wp-block-paragraph">After moving Genome Toolkit to <code>uv</code>, there is one small thing we need to check.</p>



<p class="wp-block-paragraph"><code>uv</code> created our local Python environment 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">.venv/</pre></div>



<p class="wp-block-paragraph">But Code Runner may still try to use the global Python installation on your computer. If that happens, it may not be able to find our new installed <code>genome_toolkit</code> package.</p>



<p class="wp-block-paragraph">Fortunately, this is a simple one-time fix. We just need to tell Code Runner to use the Python interpreter already selected by VS Code or VSCodium.</p>



<ol class="wp-block-list">
<li>Open the Command Palette:</li>
</ol>



<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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Ctrl + Shift + P</pre></div>



<p class="wp-block-paragraph">or on macOS:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Cmd + Shift + P</pre></div>



<ol start="2" class="wp-block-list">
<li>Search for <strong>Open User Settings</strong> and select the option with <strong>(JSON)</strong> in its name.</li>



<li>Find the existing:</li>
</ol>



<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;javascript&quot;,&quot;mime&quot;:&quot;application/json&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;JSON&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">&quot;code-runner.executorMap&quot;</pre></div>



<p class="wp-block-paragraph">section.</p>



<ol start="4" class="wp-block-list">
<li>Update only the Python entry to:</li>
</ol>



<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;javascript&quot;,&quot;mime&quot;:&quot;application/json&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;JSON&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">&quot;code-runner.executorMap&quot;: {
    &quot;python&quot;: &quot;$pythonPath -u $fullFileName&quot;
}</pre></div>



<p class="wp-block-paragraph">Leave your other language entries unchanged and save the file.</p>



<p class="wp-block-paragraph">Code Runner will now use the Python interpreter selected by the editor, which for our project should be the one inside <code>.venv/</code>.</p>



<p class="wp-block-paragraph">That means our quick:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Ctrl + Alt + N</pre></div>



<p class="wp-block-paragraph">shortcut can keep working exactly as before, but now it runs Genome Toolkit inside our new <code>uv</code> environment.</p>



<h2 class="wp-block-heading">Pro Tip #2: Automatic Formatting With Ruff</h2>



<p class="wp-block-paragraph">Here is another small setup improvement that can save us a lot of repetitive work as Genome Toolkit grows.</p>



<p class="wp-block-paragraph">When we work on the same project across many files and many sessions, formatting can slowly become inconsistent. Spacing changes, imports move around, and a tiny code change can create a much larger Git diff than it really needs to.</p>



<p class="wp-block-paragraph">For Python, we are going to use <strong>Ruff</strong>.</p>



<p class="wp-block-paragraph">Ruff is a modern Python <strong>linter</strong> and <strong>formatter</strong> built by Astral, the same team behind <code>uv</code>. A linter helps spot common code problems, while a formatter automatically keeps our Python code laid out consistently.</p>



<p class="wp-block-paragraph">And as always, Corey Schafer has an excellent detailed walkthrough if you want to understand Ruff beyond the small setup we need here:</p>



<p class="wp-block-paragraph"><strong><a href="https://youtu.be/828S-DMQog8">Python Tutorial: Ruff &#8211; A Fast Linter &amp; Formatter to Replace Multiple Tools and Improve Code Quality</a></strong></p>



<p class="wp-block-paragraph">If you use VS Code or VSCodium, the easiest setup is through the official <strong>Ruff</strong> extension published by Astral Software.</p>



<p class="wp-block-paragraph">Open the Extensions panel:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Ctrl + Shift + X</pre></div>



<p class="wp-block-paragraph">or on macOS:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Cmd + Shift + X</pre></div>



<p class="wp-block-paragraph">Search for <strong>Ruff</strong> and install or enable the official extension.</p>



<p class="wp-block-paragraph">Then open your User Settings JSON and add or verify:</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;javascript&quot;,&quot;mime&quot;:&quot;application/json&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;JSON&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">{
    &quot;[python]&quot;: {
        &quot;editor.defaultFormatter&quot;: &quot;charliermarsh.ruff&quot;,
        &quot;editor.formatOnSave&quot;: true,
        &quot;editor.codeActionsOnSave&quot;: {
            &quot;source.fixAll.ruff&quot;: &quot;explicit&quot;,
            &quot;source.organizeImports.ruff&quot;: &quot;explicit&quot;
        }
    },
    &quot;ruff.nativeServer&quot;: &quot;on&quot;
}</pre></div>



<p class="wp-block-paragraph">The most important setting for our everyday workflow 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;javascript&quot;,&quot;mime&quot;:&quot;application/json&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;JSON&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">&quot;editor.formatOnSave&quot;: true</pre></div>



<p class="wp-block-paragraph">Now every time we save a Python file, Ruff can automatically keep the formatting clean and consistent for us.</p>



<p class="wp-block-paragraph">Ruff is a development tool, not something Genome Toolkit needs in order to run. We therefore do not add it to the package&#8217;s normal runtime dependencies just to format our source code.</p>



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



<p class="wp-block-paragraph">After synchronizing the project, the repository should now be approximately:</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;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;}">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">This is still a very small project, which is good.</p>



<p class="wp-block-paragraph">We now have a proper place for the scientific 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/genome_toolkit/</pre></div>



<p class="wp-block-paragraph">and a dedicated place for our current algorithms:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">src/genome_toolkit/algorithms/</pre></div>



<p class="wp-block-paragraph">As we continue through Parts 4.x, we can add the next pieces only when we actually need them.</p>



<h2 class="wp-block-heading">What Changed and What Stayed the Same?</h2>



<p class="wp-block-paragraph">Quite a lot changed structurally in this article.</p>



<p class="wp-block-paragraph">We moved 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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Pipenv
        ↓
uv</pre></div>



<p class="wp-block-paragraph">We moved 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;}">loose genome_toolkit.py
        ↓
installable src/genome_toolkit package</pre></div>



<p class="wp-block-paragraph">And we moved 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;}">stateless genomeToolkit object
        ↓
plain algorithm functions</pre></div>



<p class="wp-block-paragraph">Our application also imports the scientific functions from the package rather than constructing an object first.</p>



<p class="wp-block-paragraph">But the important scientific parts did not change:</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;}">same input strings
same k-mer calculations
same int/list return values
same scientific results</pre></div>



<p class="wp-block-paragraph">That distinction is exactly what we wanted to see when we introduced refactoring in Part 4.1. We can improve the way our software is organized while keeping the scientific behavior we already understand.</p>



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



<p class="wp-block-paragraph">In Part 4.2, we took our original working Genome Toolkit and turned it into a modern installable Python package. We moved from Pipenv to <code>uv</code>, created the <code>src/</code> package structure, moved our existing k-mer algorithms into their new home, simplified the old class methods into plain typed functions, and updated <code>application.py</code> to use them.</p>



<p class="wp-block-paragraph">Most importantly, the scientific calculations did not change. We reorganized the project, synchronized the new environment, and then confirmed that Genome Toolkit still produces exactly the same k-mer results as before. We now have a much cleaner foundation that will be easier to expand, test, share, and eventually use in real biological experiments.</p>



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



<ul class="wp-block-list">
<li><strong><code>uv</code></strong> — Our new Python project and package manager. It creates and manages the virtual environment, installs dependencies, generates the lock file, runs our project, and helps build the package. It replaces several separate project-management tasks with one modern tool.</li>



<li><strong><code>pyproject.toml</code></strong> — The main project configuration file. It tells Python tools what Genome Toolkit is, which Python version and dependencies it needs, its package version and description, and how the project should be built. It solves the problem of keeping the important project and package configuration in one standard place.</li>



<li><strong><code>README.md</code></strong> — Human-facing project documentation. It explains what the project does and, in our case, now includes the basic commands needed to run Genome Toolkit after cloning the repository. It helps other people, and future us, understand and use the project without first reading through the source code.</li>



<li><strong><code>uv.lock</code></strong> — Records the exact dependency versions selected by <code>uv</code>. For example, if <code>pyproject.toml</code> later allows a range of Pydantic versions, <code>uv.lock</code> records the exact version actually chosen for our project. This helps different machines recreate the same environment instead of silently installing slightly different versions.</li>



<li><strong><code>.venv/</code></strong> — Genome Toolkit&#8217;s private Python environment. It contains the Python environment and installed packages used by this project, keeping them isolated from other Python projects on the same computer. This prevents one project&#8217;s dependencies from easily interfering with another.</li>



<li><strong><code>src/</code></strong> — Contains the actual installable source code, such as <code>src/genome_toolkit/</code>. It separates the Python package itself from project files such as <code>README.md</code>, <code>pyproject.toml</code>, and <code>application.py</code>, and helps us work with Genome Toolkit the same way another installed project would.</li>



<li><strong><code>__init__.py</code></strong> — Used inside package directories such as <code>genome_toolkit/</code> and <code>algorithms/</code>. In our project, it helps define the package structure and can expose a cleaner public API. For example, instead of importing <code>count_kmer</code> from <code>genome_toolkit.algorithms.kmer</code>, we can expose it through <code>genome_toolkit.algorithms</code> and use the shorter import.</li>



<li><strong><code>__all__</code></strong> — Makes the names we intentionally expose from a module or package explicit. In <code>algorithms/__init__.py</code>, it tells readers and development tools that <code>count_kmer</code> and <code>find_most_frequent_kmers</code> are part of the public algorithm API we want people to use.</li>



<li><strong><code>py.typed</code></strong> — Usually an empty marker file saying that the installed package officially provides Python type annotations. It helps external tools such as Pyright, mypy, and IDEs understand that they can use Genome Toolkit&#8217;s type hints when checking code that imports our package.</li>



<li><strong>Type hints</strong> — Extra information in function signatures that describes the kinds of values a function expects and returns. For example, <code>sequence: str</code> tells us that <code>count_kmer()</code> expects a string, while <code>-> int</code> tells us that it returns an integer. They make our code easier to understand and allow editors and type-checking tools to catch some mistakes earlier.</li>



<li><strong>Plain functions instead of class methods</strong> — Our original k-mer algorithms lived inside the <code>genomeToolkit</code> class even though they did not need to store any object state. Moving them to plain functions makes them simpler to call and keeps the scientific code focused on the calculation itself, while preserving the exact same algorithm behavior.</li>



<li><strong>Package versioning</strong> — Genome Toolkit now keeps one authoritative version in <code>pyproject.toml</code> and reads that version from the installed package metadata. Later, when we run experiments on real biological data, recording which Genome Toolkit version produced a result will become important for reproducibility and provenance.</li>
</ul>



<p class="wp-block-paragraph">The most important thing we learned is that modernizing the structure of a scientific project does not mean rewriting the science. Our algorithms still perform the same calculations, but they now live inside a project that is much easier to install, understand, maintain, and grow.</p>



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



<p class="wp-block-paragraph">Genome Toolkit is now a real modern Python package.</p>



<p class="wp-block-paragraph">But our algorithms still accept this:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">AATTTTAAAAC
HELLO
12345
???</pre></div>



<p class="wp-block-paragraph">Python does not know which one is a biological sequence.</p>



<p class="wp-block-paragraph">So in Part 4.3, we are going to solve the next problem:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">If an algorithm is supposed to work on biological sequences, should any random string be allowed to reach it?</p>
</blockquote>



<p class="wp-block-paragraph">We will introduce our first validated biological sequence models and start teaching Genome Toolkit what DNA actually looks like.</p>



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



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



<p class="wp-block-paragraph">I hope this next step in building Genome Toolkit 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 <a href="https://rebelscience.club/cryptocurrency-donations/">here</a>.</p>



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



<p class="wp-block-paragraph">Video version of this article is available here: <a href="https://youtu.be/fPLjrExTQTM">https://youtu.be/fPLjrExTQTM</a></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.2: Modernizing the Existing Python Project" width="640" height="360" src="https://www.youtube.com/embed/fPLjrExTQTM?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><item><title>Genome Toolkit. Part 4.1: Building a Scientific Python Package</title><link>https://rebelscience.club/2026/08/genome-toolkit-part-4-1-building-a-scientific-python-package/</link><guid isPermaLink="true">https://rebelscience.club/2026/08/genome-toolkit-part-4-1-building-a-scientific-python-package/</guid><pubDate>Mon, 24 Aug 2026 12:21:46 GMT</pubDate><description>In Part 4.1, we take a step back and look at where Genome Toolkit is going next. We introduce refactoring, explain why our small project is ready to grow into a proper scientific Python package, and show how this gives us a cleaner foundation for future biological tools and experiments. We also look at something pretty exciting: by building Genome Toolkit properly now, we are gradually making it AI-ready for future APIs, MCP tools, and AI agents.
</description><content:encoded><![CDATA[
<p class="wp-block-paragraph">Welcome back to the Genome Toolkit series!</p>



<p class="wp-block-paragraph">If you have been following rebelScience and our Genome Toolkit series for a while, you know that it has been quite a while since our last video. A few years, actually. And a lot has changed across software engineering, bioinformatics, and scientific research.</p>



<p class="wp-block-paragraph">In Parts 1, 2, and 3, we built our first useful bioinformatics algorithms using a very small Python project:</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;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;}">genome_toolkit/
├── .git/
├── .gitignore
├── application.py
├── genome_toolkit.py
├── Pipfile
└── Pipfile.lock</pre></div>



<p class="wp-block-paragraph">That project already works. <code>application.py</code> creates our <code>genomeToolkit</code> object, runs the two k-mer algorithms we have built so far, and gives us:</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: AATTTTAAAAC
k-mer: AA
Repeats found: 4
Most frequent k-mer: ['TTT', 'AAA']</pre></div>



<p class="wp-block-paragraph">This was exactly the right structure for learning our first algorithms. We could keep everything close together, focus on the biology and Python, and immediately see what our code produced.</p>



<p class="wp-block-paragraph">We are absolutely going to continue building Genome Toolkit. We want to add more biological sequence types, load real biological data from files and databases, add more bioinformatics algorithms, and eventually use those tools together in larger experiments.</p>



<p class="wp-block-paragraph">Before we add all of that, however, we are going to improve the structure underneath the project and turn Genome Toolkit into a small scientific Python package.</p>



<p class="wp-block-paragraph">That process is called <strong>refactoring</strong>. Refactoring means reorganizing and improving the structure of existing software without changing what its core functionality is supposed to do.</p>



<p class="wp-block-paragraph">And by doing this now, relatively early in the project, we are going to get something pretty amazing almost for free. While we are turning Genome Toolkit into a cleaner, more professional scientific Python package, we are also gradually making it <strong>AI-ready</strong>.</p>



<p class="wp-block-paragraph">We will see exactly what that means as we progress through Parts 4.x. For now, the important idea is simple: the same clean, tested Genome Toolkit that we use ourselves will also become much easier for APIs, MCP tools, and AI agents to use later, without having to rebuild our scientific logic every time.</p>



<p class="wp-block-paragraph">We will keep using the same working Genome Toolkit while we improve it step by step. <code>application.py</code> will remain our familiar test: after each major change, we can run it again and make sure our original calculations still work.</p>



<h2 class="wp-block-heading">A Note for the Biologists</h2>



<p class="wp-block-paragraph">The next few parts will contain more software engineering than Parts 1 through 3, but our biological goal is not changing. We are still building Genome Toolkit so we can work with biological sequences, run useful algorithms, and eventually combine those tools into real experiments.</p>



<p class="wp-block-paragraph">The workflow will stay familiar:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">biological data
      ↓
Genome Toolkit
      ↓
scientific result</pre></div>



<p class="wp-block-paragraph">We are simply going to make the code underneath that workflow cleaner, easier to test, and easier to expand.</p>



<p class="wp-block-paragraph">You do not need to become a Python packaging expert to use Genome Toolkit. If your main interest is biology, you can treat these parts as the engineering foundation underneath the experiments we will build later.</p>



<h2 class="wp-block-heading">What Refactoring Means for Genome Toolkit</h2>



<p class="wp-block-paragraph">Right now, our project is very simple:</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;}">application.py
      ↓
genome_toolkit.py
      ↓
two working algorithms</pre></div>



<p class="wp-block-paragraph">As Genome Toolkit grows, we want something closer 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;}">application.py
      ↓
genome_toolkit package
      ↓
biological sequences
(DNA, RNA, proteins, etc.)
      ↓
data loaders
(FASTA, NCBI, other formats and sources)
      ↓
algorithms
(k-mer analysis, future sequence algorithms, etc.)
      ↓
scientific results
(results together with useful context)</pre></div>



<p class="wp-block-paragraph">The important point is that the scientific purpose stays the same. We are not changing <code>count_kmer()</code> just because we are reorganizing the project, and we are not changing <code>find_most_frequent_kmers()</code> just because the files around it move.</p>



<p class="wp-block-paragraph">We will improve the project structure first. Later, when we add automated tests, we can look at real edge cases and deliberately decide whether any algorithm behavior needs to change.</p>



<h2 class="wp-block-heading">Why Build a Scientific Python Package?</h2>



<p class="wp-block-paragraph">Our current two-file project works, but it was designed for a much smaller job. As Genome Toolkit grows, we will need to handle more than just two algorithms.</p>



<p class="wp-block-paragraph">For example, we are going to need code for things such as:</p>



<ul class="wp-block-list">
<li>representing and checking biological sequences;</li>



<li>loading sequence data from plain-text and FASTA files;</li>



<li>running different families of bioinformatics algorithms;</li>



<li>returning scientific results with useful context;</li>



<li>testing that calculations and error cases behave correctly.</li>
</ul>



<p class="wp-block-paragraph">If all of that grows inside one file, the project quickly becomes difficult to understand and change. A package lets us separate those jobs into smaller parts that each have a clear purpose.</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;:false,&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;:false,&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;}">genome_toolkit/
├── sequence/
├── load/
└── algorithms/</pre></div>



<p class="wp-block-paragraph"><code>sequence/</code> can contain code for biological sequences such as DNA. <code>load/</code> can contain code for reading biological data from files. <code>algorithms/</code> can contain the scientific calculations themselves.</p>



<p class="wp-block-paragraph">This also makes Genome Toolkit much easier to reuse. Instead of treating it as a couple of Python files that belong to one project folder, we will be able to install it and use it like a normal Python library:</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;}">import genome_toolkit</pre></div>



<p class="wp-block-paragraph">That means the same tested scientific code can later be used from another Python script, a Jupyter notebook, a larger research project, a web application, or another tool.</p>



<p class="wp-block-paragraph">For us, this is also a useful step from an educational project toward a real portfolio project. We are not only showing that we can write individual bioinformatics algorithms. We are showing that we can organize those algorithms into scientific software that other people can install, test, reuse, and expand.</p>



<p class="wp-block-paragraph">Our goal with this refactoring is to move from the following type of simple script output:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">[Genome Toolkit Initiated]

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



<p class="wp-block-paragraph">To a scientific results like these:</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;javascript&quot;,&quot;mime&quot;:&quot;application/x-json&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;JSON&quot;,&quot;language&quot;:&quot;JSON&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;json&quot;}">{
  &quot;metadata&quot;: {
    &quot;toolkit_version&quot;: &quot;0.1.0&quot;,
    &quot;algorithm&quot;: &quot;count_kmer&quot;,
    &quot;timestamp&quot;: &quot;2026-08-24T09:30:53.399181Z&quot;
  },
  &quot;inputs&quot;: {
    &quot;sequence&quot;: {
      &quot;identifier&quot;: &quot;M57671.1&quot;,
      &quot;description&quot;: &quot;Octodon degus insulin mRNA, complete cds&quot;,
      &quot;length&quot;: 126
    }
  },
  &quot;parameters&quot;: {
    &quot;kmer&quot;: &quot;CCTT&quot;
  },
  &quot;output&quot;: {
    &quot;count&quot;: 5
  }
}

{
  &quot;metadata&quot;: {
    &quot;toolkit_version&quot;: &quot;0.1.0&quot;,
    &quot;algorithm&quot;: &quot;find_most_frequent_kmers&quot;,
    &quot;timestamp&quot;: &quot;2026-08-24T09:30:53.400405Z&quot;
  },
  &quot;inputs&quot;: {
    &quot;sequence&quot;: {
      &quot;identifier&quot;: &quot;M57671.1&quot;,
      &quot;description&quot;: &quot;Octodon degus insulin mRNA, complete cds&quot;,
      &quot;length&quot;: 126
    }
  },
  &quot;parameters&quot;: {
    &quot;k_len&quot;: 5
  },
  &quot;output&quot;: {
    &quot;kmers&quot;: [
      &quot;CTTGG&quot;,
      &quot;TTGGG&quot;,
      &quot;TGGGC&quot;,
      &quot;GGGCC&quot;
    ],
    &quot;frequency&quot;: 6
  }
}</pre></div>



<h2 class="wp-block-heading">Preparing Genome Toolkit for APIs, MCP, and AI Agents</h2>



<p class="wp-block-paragraph">There is another reason this structure is becoming increasingly useful.</p>



<p class="wp-block-paragraph">Today, scientific software does not have to be used only by someone manually writing Python code. The same package can later be connected to a web interface, an API, or an AI agent.</p>



<p class="wp-block-paragraph">An <strong>API</strong>, or Application Programming Interface, gives one program a structured way to use another program. <strong>MCP</strong>, or Model Context Protocol, gives AI systems a standardized way to connect to external tools.</p>



<p class="wp-block-paragraph">We will explain both properly when they become relevant. For now, the important idea is simply that Genome Toolkit can become the tested scientific tool underneath those systems.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2.png"><img decoding="async" width="1280" height="720" src="https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-1280x720.png" alt="" class="wp-image-2440" srcset="https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-1280x720.png 1280w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-512x288.png 512w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-768x432.png 768w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-1536x864.png 1536w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-24x14.png 24w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-36x20.png 36w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2-48x27.png 48w, https://rebelscience.club/wp-content/uploads/2026/08/apu_mcp-2.png 1672w" sizes="(max-width: 1280px) 100vw, 1280px" /></a></figure>
</div>


<p class="wp-block-paragraph">Imagine asking an AI agent:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Find 100 genomes of this bacterium, run our k-mer analyses on them, compare the results, and prepare a summary.</p>
</blockquote>



<p class="wp-block-paragraph">Without dedicated scientific tools, the AI has to figure out much of that workflow by itself. It may search for genome sequences from different places, choose how to download them, write analysis code while it is working, pick libraries, and decide how to organize the calculations.</p>



<p class="wp-block-paragraph">That flexibility can be useful, but it creates a problem for science. Modern language models are <strong>non-deterministic</strong>, which means they can make different choices across separate runs. If the AI is also writing the algorithms and deciding where the data comes from every time, reproducing exactly the same experiment becomes much harder.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://rebelscience.club/wp-content/uploads/2026/08/determ-1.png"><img decoding="async" width="1280" height="720" src="https://rebelscience.club/wp-content/uploads/2026/08/determ-1-1280x720.png" alt="" class="wp-image-2435" srcset="https://rebelscience.club/wp-content/uploads/2026/08/determ-1-1280x720.png 1280w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1-512x288.png 512w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1-768x432.png 768w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1-1536x864.png 1536w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1-24x14.png 24w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1-36x20.png 36w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1-48x27.png 48w, https://rebelscience.club/wp-content/uploads/2026/08/determ-1.png 1672w" sizes="(max-width: 1280px) 100vw, 1280px" /></a></figure>
</div>


<p class="wp-block-paragraph">Now imagine that the AI can use Genome Toolkit instead.</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">AI agent
    ↓
Genome Toolkit tools
    ↓
tested scientific calculations
    ↓
structured results</pre></div>



<p class="wp-block-paragraph">The AI can still help organize the work, choose which tools to call, compare many results, and prepare a report. But the actual k-mer calculation can come from the same <code>count_kmer()</code> function that we already wrote, understand, and test.</p>



<p class="wp-block-paragraph">The same idea applies to loading biological data. Instead of inventing a new FASTA parser every time, the AI can use our loader. Instead of returning a number with no context, Genome Toolkit can later return a structured result that tells us which sequence, parameters, algorithm, and software version produced it.</p>



<p class="wp-block-paragraph">This is where <strong>reproducibility</strong> and <strong>provenance</strong> become important. Reproducibility means that we should be able to repeat the same scientific calculation using the same data, algorithm, parameters, and software version. Provenance means keeping enough information to understand where a result came from.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://rebelscience.club/wp-content/uploads/2026/08/prov-1.png"><img decoding="async" width="1280" height="720" src="https://rebelscience.club/wp-content/uploads/2026/08/prov-1-1280x720.png" alt="" class="wp-image-2437" srcset="https://rebelscience.club/wp-content/uploads/2026/08/prov-1-1280x720.png 1280w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1-512x288.png 512w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1-768x432.png 768w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1-1536x864.png 1536w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1-24x14.png 24w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1-36x20.png 36w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1-48x27.png 48w, https://rebelscience.club/wp-content/uploads/2026/08/prov-1.png 1672w" sizes="(max-width: 1280px) 100vw, 1280px" /></a></figure>
</div>


<p class="wp-block-paragraph">We are not going to build all of that in this article. We will introduce each piece when we actually need it and can immediately see what problem it solves.</p>



<p class="wp-block-paragraph">For now, the high-level idea is enough:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">Python script / notebook / web app / AI agent
                    ↓
              Genome Toolkit
                    ↓
          tested scientific code
                    ↓
             scientific result</pre></div>



<p class="wp-block-paragraph">Genome Toolkit itself will stay focused on the science. Web servers, APIs, MCP connections, authentication, databases, and AI-agent logic can live outside the package and use Genome Toolkit as the scientific core underneath them.</p>



<h2 class="wp-block-heading">What We Will Build Next</h2>



<p class="wp-block-paragraph">Over the next few parts, we will gradually turn the same working project into a modern scientific Python package.</p>



<p class="wp-block-paragraph">At a high level, we will:</p>



<ul class="wp-block-list">
<li>modernize the project with <code>uv</code> and a proper Python package structure;</li>



<li>add validated biological sequence objects such as <code>DNA</code>;</li>



<li>load biological data from plain-text and FASTA files;</li>



<li>return more useful scientific results;</li>



<li>add automated tests and clearer error behavior.</li>
</ul>



<p class="wp-block-paragraph">We do not need to understand all of those pieces yet. We will introduce them one at a time, when we actually build and use them.</p>



<p class="wp-block-paragraph">The important thing to remember is where we are going:</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;python&quot;,&quot;mime&quot;:&quot;text/x-python&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;Python&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}">biological data
      ↓
Genome Toolkit
      ↓
tested algorithms
      ↓
scientific results</pre></div>



<p class="wp-block-paragraph">Everything else we add is there to make that workflow easier to use, easier to trust, and easier to expand.</p>



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



<p class="wp-block-paragraph">Our original Genome Toolkit project was exactly what we needed for learning our first algorithms. Now we want to grow it into a scientific Python package that can handle biological sequences, external data, more algorithms, better results, and automated testing without becoming difficult to maintain.</p>



<p class="wp-block-paragraph">The scientific goal stays the same. We are still building a practical bioinformatics toolkit, and our existing k-mer algorithms remain the starting point.</p>



<p class="wp-block-paragraph">The new package structure will also make Genome Toolkit much easier to reuse from other Python projects, notebooks, future web applications, APIs, MCP tools, and AI agents. Most importantly, it gives us a cleaner foundation for building scientific workflows that are easier to test, understand, and reproduce.</p>



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



<p class="wp-block-paragraph">In <strong>Genome Toolkit Part 4.2</strong>, we will finally start changing the project.</p>



<p class="wp-block-paragraph">We will begin by running our current <code>application.py</code> one more time and confirming the familiar output. Then we will modernize the same project with <code>uv</code>, create a proper Python package structure, move our existing k-mer algorithms into it, and run <code>application.py</code> again.</p>



<p class="wp-block-paragraph">That gives us a very simple first goal: change how Genome Toolkit is organized while keeping the scientific calculations working.</p>



<p class="wp-block-paragraph">From there, we will continue one useful step at a time.</p>



<p class="wp-block-paragraph">I hope this introduction to building our scientific Python package 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 <a href="https://rebelscience.club/cryptocurrency-donations/">here</a>.</p>



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



<p class="wp-block-paragraph">A video version of this article:</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.1: Building a Scientific Python Package" width="640" height="360" src="https://www.youtube.com/embed/tkaVS_LCfpo?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>



<p class="wp-block-paragraph"></p>
]]></content:encoded></item></channel></rss>