ST005: HasSrcLayout

Overview

Property Value
ID ST005
Name HasSrcLayout
Group structure
Severity NOTE

Description

Checks that the package uses the src/ layout structure.

The src layout places your package code inside a src/ directory, which provides better isolation and prevents common import issues during development.

What it checks

The check verifies:

  1. A src/ directory exists in the package root
  2. The src/ directory contains at least one package (a directory with __init__.py)

Why it matters

The src layout prevents a common pitfall in Python development:

  • Import isolation - Without src layout, Python may accidentally import your local development code instead of the installed package
  • Realistic testing - Tests run against the installed package, not the development source
  • Build verification - Ensures your package installs correctly before release

Flat layout problems

With a flat layout (my_package/ at root), this can happen:

# You think you're testing the installed package...
import my_package

# But Python imports from the local directory instead!
# Bugs might not be caught until after release.

Src layout solution

With src layout (src/my_package/):

# This always imports the installed package
import my_package

# Your tests verify the real installation behavior

How to fix

Step 1: Create the src directory

mkdir src

Step 2: Move your package

mv my_package src/

Step 3: Update pyproject.toml

Most modern build backends auto-detect src layout. If needed, configure explicitly:

For Hatchling:

[tool.hatch.build.targets.wheel]
packages = ["src/my_package"]

For Setuptools:

[tool.setuptools.packages.find]
where = ["src"]

For Flit:

[tool.flit.module]
name = "my_package"

Step 4: Verify

pip install -e .
python -c "import my_package; print(my_package.__file__)"

The output should show the installed location, not src/my_package.

Directory structure example

Before (flat layout):

my-project/
    my_package/
        __init__.py
        module.py
    tests/
    pyproject.toml

After (src layout):

my-project/
    src/
        my_package/
            __init__.py
            module.py
    tests/
    pyproject.toml

Configuration

Skip this check

[tool.pycmdcheck]
skip = ["ST005"]

CLI

pycmdcheck --skip ST005