Atlas writes unit tests for an untested Python module by reading the module, enumerating its public functions with the lsp tool's documentSymbol operation, grepping your existing tests/ directory for the conventions the repo already uses, writing the new test file with the write tool, and then running pytest with the bash tool. The run is the point: a test that was never executed is not a test. In a repo with a pyproject.toml, uv manages the dependencies and ruff format keeps the new test file consistent with the rest of the package.
How does Atlas write pytest tests for a Python module that has none?
Atlas reads the target Python module, then uses the lsp tool's documentSymbol operation to enumerate its exported symbols so no public function is missed. Only after that does Atlas write the test file. In 2026 the sequence matters: enumerate first, then write, then run pytest with the bash tool.
Enumeration comes first because coverage of a Python module is a question of symbols, not of vibes. A module like src/billing/invoices.py may export compute_total, apply_discount, and a Decimal-rounding helper that everyone forgets. The lsp tool's documentSymbol operation lists all of them. Atlas indexes code by AST declarations using tree-sitter, not blind line windows, so the def and class boundaries Atlas works from are real boundaries rather than arbitrary slices. The result is a tests/test_invoices.py that has a case per public function instead of one happy-path test for the function that happened to be at the top of the file.
How does Atlas match the repo's existing pytest conventions?
Atlas greps for an existing test file to copy the repo's framework, import style, and naming convention. If your Python package puts fixtures in tests/conftest.py and uses pytest.mark.parametrize for table cases, the new file does too, rather than inventing a second style in the same 2026 codebase.
Convention copying is the difference between a test file that merges and one that starts an argument in review. Atlas searches code with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, so asking how the repo fakes the database finds the shared fixture even when the fixture is named something nobody would guess. grep then confirms the literal pattern: whether tests import from the package root or use relative imports, whether fixtures come from tests/conftest.py, whether assertions use pytest.raises for the error paths, and whether a Django or FastAPI test client is wired up already. The new pytest file inherits all of it.
How do I make Atlas actually run pytest instead of just writing tests?
Atlas runs the suite with the bash tool, which is a permission-gated tool call like any other. Running pytest is not optional in this workflow: the run is the point, because a test that was never executed is not a test. Output over 2000 lines or 50 KB is truncated, with the full log saved to a file.
The truncation behavior is worth knowing before you point Atlas at a large Python suite. When pytest output exceeds 2000 lines or 50 KB, the bash tool truncates what it shows and saves the full log to a file you can read, so a long traceback dump does not evict the module under test from context. Atlas then reads the failures and iterates with edit until the suite is green. On a big module, keeping progress in a todowrite list means the ten public functions you set out to cover do not silently become the three that were easy.
How do I review Python test files Atlas writes before they hit disk?
Atlas writes the new spec file with the write tool, which shows the diff in the permission prompt before anything lands on disk. Every Atlas tool call is gated against 3 rule types, allow, ask, and deny, so a new tests/test_invoices.py arrives as an approvable diff, not a surprise file in git status.
Two Atlas properties do the work here. Atlas computes a unified diff for every file edit and surfaces it for approval before writing, so you read the pytest cases before they exist. Atlas snapshots file changes as git patches so edits can be diffed and rolled back, so an iteration that mangled a fixture is one revert away. Review matters more for tests than people expect: a test that mocks the very function it claims to exercise will pass forever and prove nothing, and the only place to catch that is the diff. Run ruff format over the accepted file and it matches the rest of the package.
What does the finished Python test workflow look like end to end?
Start Atlas in a repo with a pyproject.toml, then follow the 5 documented steps: read the module, enumerate its exports with the lsp tool's documentSymbol operation, grep an existing test for conventions, write the spec with the write tool, and run pytest with bash, editing until the suite is green.
The loop is short. Atlas reads src/billing/invoices.py, enumerates the exported symbols with the lsp tool, greps tests/ for the conventions, writes tests/test_invoices.py with the write tool, runs pytest with the bash tool, reads the failures, and edits until the suite passes. uv is the package manager, so a test that needs a new library declares it and uv installs it. ruff format is the formatter, so the file lands consistent. Atlas reads git branches, status, and diffs, and can stage and create commits on your behalf, so the new coverage arrives as one clean commit.
Step by step
- 01Run atlas in a repo with a pyproject.toml or requirements.txt and let it read your package layout, virtualenv, and installed dependencies.
- 02Have Atlas read the untested module, then use the lsp tool's documentSymbol operation to enumerate its exported symbols so no public function is missed.
- 03Grep tests/ for an existing test file to copy the repo's framework, import style, fixture location in conftest.py, and naming convention.
- 04Write the new test file with the write tool, which shows the diff in the permission prompt before anything lands on disk.
- 05Run the suite with the bash tool by invoking pytest, and read the failures; output over 2000 lines or 50 KB is truncated and the full log is saved to a file you can read.
- 06Iterate with edit until pytest is green, keeping progress in a todowrite list when the module is large.
- 07Install any new test dependency with uv so the pyproject.toml stays accurate.
- 08Run ruff format over the new test file, then let Atlas stage and commit the added coverage.
Frequently asked questions
- how to add pytest tests to a python module that has no tests
- Point Atlas at the module. Atlas reads it, enumerates its exported symbols with the lsp tool's documentSymbol operation, greps your tests/ directory for the existing conventions, writes the test file with the write tool, and runs pytest with the bash tool until the suite is green.
- can an ai agent actually run my python tests or just write them
- Atlas runs them. The bash tool executes pytest and Atlas reads the failures, then iterates with edit. The run is the point in this workflow, because a test that was never executed is not a test.
- will atlas follow my existing conftest.py fixtures
- Yes. Atlas greps for an existing test file to copy the repo's framework, import style, and naming convention, which includes fixtures defined in tests/conftest.py. It copies the repo's conventions rather than inventing its own.
- what happens when pytest output is too long for the agent context
- The Atlas bash tool truncates output over 2000 lines or 50 KB and saves the full log to a file you can read. A long pytest traceback dump therefore does not push the Python module under test out of context.
- how do i review a test file an ai wrote before it is created
- The Atlas write tool shows the diff in the permission prompt before anything lands on disk, and Atlas computes a unified diff for every file edit and surfaces it for approval before writing. Every tool call is permission-gated against allow, ask, and deny rules.
- does atlas work with uv and ruff
- Yes. In a Python repo, uv is the package manager Atlas uses to install test dependencies and ruff format is the formatter it runs over the new file, so the generated pytest file matches the rest of the package.
- how does atlas keep track of coverage progress on a large python module
- Atlas keeps progress in a todowrite list when the module is large, so every public function enumerated by the lsp tool's documentSymbol operation is accounted for rather than dropped once the easy cases pass.
Try Atlas in your terminal
The terminal-native AI coding agent. Free core, single binary.
Install AtlasRelated guides
Write Unit Tests for Untested Code with Atlas in 2026
How to write unit tests for untested code with Atlas in 2026: the lsp tool enumerates exported symbols, grep copies repo conventions, and bash actually runs the suite.
Atlas for Python in 2026
Atlas is a terminal-native AI coding agent for Python in 2026. Run it in a repo with a pyproject.toml or requirements.txt and review every diff before it lands.
Audit a Python Repo with Parallel Subagents in Atlas (2026)
Audit a Python repo with parallel Atlas subagents in 2026. Slice by package, launch read-only explore tasks, and merge findings without flooding your context.
Run the Test Suite and Triage the Failures in Python with Atlas (2026)
How Atlas runs pytest and triages a wall of Python failures in 2026: bash truncates at 2000 lines, saves the full log, and grep groups failures into a todowrite list.
Document a Python Module With a README Using Atlas (2026)
Atlas writes Python docs from source, not memory: lsp documentSymbol lists the real exports, read supplies behavior, and every code sample is proven with pytest.
Debug a Single Failing Test in Python with Atlas (2026)
How Atlas debugs one failing pytest test in 2026: run it in isolation with a -k filter, walk the call path with lsp goToDefinition, and fix the code, not the assertion.
Refactor a legacy module in Python with Atlas (2026)
Refactor a legacy Python module with Atlas in 2026: enumerate callsites with lsp findReferences, restructure with apply_patch, and prove behavior with pytest.
Plan a Multi-File Change Before Editing in Python with Atlas in 2026
Plan a multi-file Python change before editing in 2026. Atlas's plan agent denies edit for every path except .atlas/plans/*.md, then plan_exit hands off to build.