Manual Setup: Tutorial 1 — Your First Delivery
If you'd rather run commands by hand instead of using setup.py, follow these steps. Run them from a directory where you want the tutorial project created (e.g. ~/projects or cd $(mktemp -d)).
1. Create the project skeleton
mkdir -p tutorial-ascii-art/src/ascii_art tutorial-ascii-art/tests/fixtures
cd tutorial-ascii-art
touch src/__init__.py src/ascii_art/__init__.py tests/__init__.py
src/ascii_art/__init__.py is intentionally empty — that's the file nWave will fill in during delivery.
2. Create pyproject.toml
cat > pyproject.toml << 'EOF'
[project]
name = "ascii-art"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = []
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
EOF
3. Create .gitignore
cat > .gitignore << 'EOF'
.venv/
__pycache__/
*.pyc
.pytest_cache/
.mutmut-cache/
docs/feature/
docs/evolution/
.nwave/
.develop-progress.json
EOF
4. Create the test fixture
A 4x4 PPM image with a white diagonal on a black background, used by all three tests.
cat > tests/fixtures/diagonal.ppm << 'EOF'
P3
4 4
255
255 255 255 0 0 0 0 0 0 0 0 0
0 0 0 255 255 255 0 0 0 0 0 0
0 0 0 0 0 0 255 255 255 0 0 0
0 0 0 0 0 0 0 0 0 255 255 255
EOF
5. Create the acceptance tests
These three tests define the complete feature contract. nWave will write the implementation to make them pass.
# tests/test_ascii_art.py
"""Acceptance tests for image-to-ASCII converter.
These 3 tests define the complete feature contract.
nWave will implement the code to make them pass.
"""
from pathlib import Path
FIXTURES = Path(__file__).parent / "fixtures"
def test_converts_image_to_ascii_with_correct_width():
"""Given a PPM image
When I convert it to ASCII art with width=20
Then every line of output is exactly 20 characters wide."""
from ascii_art import image_to_ascii
result = image_to_ascii(FIXTURES / "diagonal.ppm", width=20)
lines = result.strip().split("\n")
assert len(lines) > 0
assert all(len(line) == 20 for line in lines)
def test_output_uses_only_density_characters():
"""Given a PPM image
When I convert it to ASCII art
Then the output contains only characters from the density ramp."""
from ascii_art import image_to_ascii
DENSITY = " .:-=+*#%@"
result = image_to_ascii(FIXTURES / "diagonal.ppm", width=10)
for char in result:
assert char in DENSITY or char == "\n"
def test_bright_pixels_produce_dense_characters():
"""Given an image with a white diagonal on black background
When I convert it to ASCII art
Then bright pixels map to dense characters like @ or #
And dark pixels map to sparse characters like space or dot."""
from ascii_art import image_to_ascii
result = image_to_ascii(FIXTURES / "diagonal.ppm", width=4)
lines = result.strip().split("\n")
# The diagonal image has white pixels on the diagonal
# First line: bright pixel at position 0, dark elsewhere
first_line = lines[0]
assert first_line[0] in "#%@" # bright pixel -> dense char
assert first_line[-1] in " .:" # dark pixel -> sparse char
6. Create the virtualenv and install pytest
python3 -m venv .venv
source .venv/bin/activate
pip install pytest
Windows users: Replace
source .venv/bin/activatewith.venv\Scripts\activate.
7. Initialize git
nWave uses commits to track its TDD progress, so the project must be a git repo.
git init
git add -A
git commit -m "feat: ascii-art starter project (empty implementation, 3 failing tests)"
Verify
You should now have:
- A
tutorial-ascii-art/directory containingsrc/ascii_art/__init__.py(empty),tests/test_ascii_art.py,tests/fixtures/diagonal.ppm,pyproject.toml, and.gitignore - A
.venv/virtual environment withpytestinstalled - A clean git repository with one initial commit
- Three failing acceptance tests (run
pytest tests/ -vto confirm — they fail becauseascii_art.image_to_asciidoesn't exist yet)
You're ready to start the tutorial.