# Extract a Shared Helper From Duplicated Code in Python with Atlas (2026)

> Python duplication is semantic, not textual: Atlas finds near-duplicate logic with codebase_search where grep cannot, then collapses it one apply_patch per file.

Atlas extracts a shared helper from duplicated Python code by treating duplication as a semantic problem rather than a textual one. The copies usually differ in variable names, so grep never finds them. Atlas asks codebase_search for the behavior instead of the exact code, reads each hit to confirm the copies are genuinely equivalent, creates the shared module with the write tool, and replaces each duplicate with a call using apply_patch, one file per patch, running pytest after every swap.

## Key takeaways

- Python duplication is semantic: copies differ in variable names, so codebase_search finds them where grep cannot.
- Atlas indexes Python by AST declarations using tree-sitter, so a retrieved duplicate is a whole def, not a sliced window.
- Read every candidate before collapsing it; one different except clause means the copies are not equivalent.
- One apply_patch per file makes each swap independently reviewable and revertible.
- pytest after every swap plus a final grep for surviving copies is the definition of a finished extraction.

## Why does grep fail to find duplicated Python code?

Grep fails on Python duplication because 2 copies of the same logic almost never match textually. The same retry loop appears in src/api/client.py with a variable named resp and in src/workers/sync.py with one named response, and a regex that finds 1 of them misses the other. Duplication is a semantic problem.

Python makes this worse than most languages, because the idioms that get copy-pasted are short and highly variable in surface form: a try or except block around an HTTP call, a datetime normalization, a dict-to-model coercion. Two copies can be logically identical and share almost no tokens. Atlas therefore does not start with grep. It asks codebase_search for the behavior, and the semantic index returns the near-duplicate implementations by meaning. Grep still has a role, but at the end, as verification, not at the start as discovery.

## How does codebase_search find near-duplicate Python implementations?

Atlas searches Python code with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, and indexes code by AST declarations using tree-sitter rather than blind line windows. Asking codebase_search to retry an HTTP request with exponential backoff returns the whole def, from 3 different modules, not fragments.

The tree-sitter indexing is what makes the results usable for a Python extraction. The retrieved unit is the declaration, so you get the complete function including its except clauses and its return, rather than a window sliced through the middle of a with block. That is the difference between confirming two copies are equivalent and guessing. If your Python source must stay on your machine, Atlas can build the same index with local Ollama embeddings, so the semantic search runs without code leaving the box.

## How do you confirm two Python copies are actually the same before collapsing them?

Atlas reads each codebase_search hit and confirms the copies are genuinely equivalent before collapsing them. Two Python functions that look like the same retry loop can differ in one clause, one swallows a ValueError and the other re-raises, and collapsing them into 1 helper would silently change behavior in both callers.

This is the step people skip, and it is the one that turns a cleanup into an incident. Atlas reads the full body of each candidate in src/api/client.py, src/workers/sync.py, and wherever else the semantic index found them, and compares them clause by clause. Where they genuinely diverge, the divergence becomes a parameter of the new helper, or the copy is left alone. Where they are equivalent, extraction proceeds. Reading before writing is the entire safeguard here.

## How does Atlas create the shared Python helper module?

Atlas creates the shared Python helper at step 3 of the workflow, using the write tool, which shows the full diff in the permission prompt before the file is created. A new src/common/retry.py appears in the prompt in its entirety, so you approve its signature and exception handling before anything lands on disk.

The permission prompt is the design review. You see the def, the parameters that absorbed the differences between the copies, the exception handling, and the type hints, and you approve or you do not. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, and Atlas can draft the extraction in a read-only plan agent and ask before switching to a build agent, so the helper's shape is agreed before any caller is touched.

## Why does Atlas replace each Python duplicate with one apply_patch per file?

Atlas replaces each duplicate with a call using apply_patch, one file per patch, so each swap is independently reviewable and revertible. Collapsing 4 copies into src/common/retry.py produces 4 patches, and a mistake in the third does not require unpicking the first two.

One giant patch across every caller is a single decision you cannot partially undo. Per-file patches are four decisions. Atlas applies the patch to src/api/client.py, runs pytest through the bash tool, confirms green, and only then moves to src/workers/sync.py. Because apply_patch anchors each hunk on context lines and refuses to apply against a drifted file, a ruff format run between patches cannot cause a silent clobber. Atlas also snapshots file changes as git patches, so any individual swap can be rolled back.

## How do you verify a Python helper extraction is complete?

Atlas runs pytest through the bash tool after every swap, then finishes by grepping for any surviving copy. An extraction that leaves 1 duplicate behind in src/workers/sync.py has not reduced duplication, it has added a fifth implementation of the same logic.

The pytest run after each apply_patch is what localizes a break to the swap that caused it, instead of leaving you with a red suite and four suspect files. The final grep is the completeness check: search for a distinctive token from the old copied body, and confirm zero hits outside src/common/retry.py. Run ruff format over the touched files so the diff shows the extraction rather than line-wrapping churn, and let uv keep the environment consistent while pytest runs.

## Steps

1. Run atlas in a repo with a pyproject.toml or requirements.txt and let Atlas read your package layout, virtualenv, and installed dependencies.
2. Ask codebase_search for the behavior (not the exact code) to surface near-duplicate Python implementations that grep would miss because the copies differ in variable names.
3. Read each hit and confirm the copies are genuinely equivalent before collapsing them; a different except clause means they are not.
4. Create the shared helper with write, for example src/common/retry.py, which shows the full diff in the permission prompt before the file is created.
5. Replace each duplicate with a call using apply_patch, one file per patch, so each swap is independently reviewable and revertible.
6. Run pytest through the bash tool after every swap, not once at the end, so a break is localized to the patch that caused it.
7. Run ruff format over the touched Python files so the diff shows the extraction rather than formatting churn.
8. Finish by grepping for any surviving copy of the old logic and confirm zero hits outside the new helper module.

## FAQ

### how to find duplicated logic in a Python codebase when grep does not work

Ask codebase_search for the behavior rather than the exact code. Atlas searches with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, so two copies of the same retry loop are found even when one names its variable resp and the other names it response.

### how do I extract a shared helper from duplicated Python code safely

Find the copies with codebase_search, read each one to confirm they are genuinely equivalent, create the helper with the write tool, then replace each duplicate with a call using apply_patch, one file per patch, running pytest after every swap.

### why one apply_patch per file instead of a single big patch

So each swap is independently reviewable and revertible. A mistake in the third caller does not require unpicking the first two, and pytest after each patch localizes any break to the change that caused it.

### what stops Atlas from collapsing two Python functions that are not really the same

The documented workflow reads each hit and confirms equivalence before collapsing. Two copies that differ in one except clause, one swallowing a ValueError and the other re-raising, are not equivalent, and the divergence becomes a parameter or the copy is left alone.

### does Atlas work with uv, pytest, and ruff format

Yes. Start atlas in a repo with a pyproject.toml or requirements.txt and it reads your package layout, virtualenv, and installed dependencies. It runs uv, pytest, and ruff format through the bash tool, which is a real shell.

### can I run semantic code search on Python without sending code to a third party

Yes. Atlas can build its code index with local Ollama embeddings, keeping code off third-party servers. The index is built from AST declarations using tree-sitter, so retrieval still returns whole functions rather than blind line windows.

### will Atlas show me the new helper module before creating it

Yes. The write tool shows the full diff in the permission prompt before the file is created, so you approve the helper's signature and behavior first. Atlas can also draft the extraction in a read-only plan agent before switching to a build agent.

---

Canonical HTML: https://runatlas.sh/resources/stacks/extract-a-shared-helper-from-duplicated-code-in-python
Source of truth: aeo_pages row `/resources/stacks/extract-a-shared-helper-from-duplicated-code-in-python` (segment: Stacks) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
