Skip to main content

Add your description here

Project description

pytest-fsd

FSD Architecture Validation for Python Projects.

pytest-fsd автоматически проверяет архитектуру вашего Python-проекта на соответствие методологии Feature-Sliced Design.

Использует гибридный подход: динамические проверки через pytest-archon + статический AST-анализ + проверка файловой структуры.

Установка

pip install pytest-fsd
# или
uv add --dev pytest-fsd

Использование

1. Настройка pyproject.toml

[tool.pytest_fsd]
base_path = "src"
layers = ["app", "windows", "widgets", "features", "entities", "shared"]

2. Создание теста

# tests/test_architecture.py
from pytest_fsd import validate_fsd_architecture

def test_project_architecture():
    validate_fsd_architecture()

3. Запуск

pytest tests/test_architecture.py -vv

Архитектура библиотеки

Каждое правило — это папка внутри src/pytest_fsd/rules/<rule_name>/ с:

  • __init__.py — логика проверки (функция check(config, project_root) -> List[Violation])
  • README.md — описание правила, примеры, rationale
src/pytest_fsd/
  __init__.py           # Фасад: validate_fsd_architecture()
  config.py             # Чтение [tool.pytest_fsd] из pyproject.toml
  _lib/                 # Общие утилиты
    violations.py       # Единый Violation dataclass
    ast_utils.py        # AST-парсинг импортов
    fs_utils.py         # Файловые утилиты, константы сегментов
  rules/
    forbidden_imports/          # pytest-archon: слои импортируют только нижележащие
    no_cross_imports/           # pytest-archon: слайсы в одном слое независимы
    no_public_api_sidestep/     # AST: импорт только через __init__.py слайса
    no_layer_public_api/        # FS: слоевые папки без __init__.py
    no_ui_in_app/               # AST: запрет UI-фреймворков в app
    repetitive_naming/          # FS: файлы не дублируют имя слайса
    no_segmentless_slices/      # FS: слайс содержит хотя бы один сегмент
    segments_by_purpose/        # FS: запрет utils/helpers/components/hooks
    ambiguous_slice_names/      # FS: имена слайсов ≠ имена сегментов shared
    no_segments_on_sliced_layers/ # FS: в слайсовых слоях не должно быть сегментов напрямую
    public_api/                 # FS: каждый слайс должен иметь __init__.py

Матрица покрытия правил Steiger

Полный список правил из Steiger FSD Plugin и их статус в pytest-fsd:

# Steiger Rule pytest-fsd Status Описание
1 forbidden-imports / no-higher-level-imports Полностью Слои импортируют только нижележащие слои
2 no-cross-imports Полностью Слайсы в одном слое независимы друг от друга
3 no-public-api-sidestep Полностью Импорт из чужого слайса только через __init__.py
4 public-api Полностью Каждый слайс и сегмент shared обязан иметь __init__.py
5 no-layer-public-api Полностью Папки слоев (features/, entities/) не должны содержать __init__.py
6 segments-by-purpose Полностью Запрет utils, helpers, hooks, components, modals, types, constants и др.
7 no-segmentless-slices Полностью Слайс обязан содержать хотя бы один стандартный сегмент
8 repetitive-naming Полностью Файлы не дублируют имя слайса (user/user_model.pyuser/model.py)
9 no-ui-in-app Полностью Слой app не должен импортировать UI-фреймворки
10 ambiguous-slice-names Полностью Имена слайсов не совпадают с сегментами shared/
11 no-segments-on-sliced-layers Полностью В слайсовых слоях нет прямых папок-сегментов
12 inconsistent-naming 🔶 Ruff Обеспечивается плагином N (pep8-naming) в Ruff
13 import-locality 🔶 Ruff Обеспечивается плагином TID (flake8-tidy-imports) в Ruff
14 typo-in-layer-name 🔶 Конфигурация Покрывается блоком [tool.pytest_fsd].layers в pyproject.toml
15 no-processes 🔶 Конфигурация Слой processes deprecated; просто не включайте его в layers
16 excessive-slicing Опционально Более 20 слайсов в одном слое (порог: 20)
17 insignificant-slice 🟡 Ручная проверка Требует анализа графа импортов для определения "незначительных" слайсов
18 no-file-segments Опционально Сегмент как файл (model.py) вместо папки (model/)
19 shared-lib-grouping Опционально Более 15 файлов в shared/lib без группировки
20 no-reserved-folder-names Опционально Подпапки в сегментах не должны совпадать с именами сегментов

Легенда

Статус Значение
Полностью Правило полностью автоматизировано и выполняется при каждом запуске pytest
Опционально Правило автоматизировано, но включается через extra_rules в pyproject.toml
🔶 Ruff / Конфигурация Покрывается внешними инструментами (Ruff) или конфигурацией pyproject.toml
🟡 Ручная проверка Требует субъективной оценки или сложного анализа, который лучше производить вручную при code review

Включение дополнительных правил

Добавьте в pyproject.toml:

[tool.pytest_fsd]
base_path = "src"
layers = ["app", "windows", "widgets", "features", "entities", "shared"]
extra_rules = [
    "excessive-slicing",       # ≤ 20 слайсов на слой
    "shared-lib-grouping",     # ≤ 15 файлов в shared/lib
    "no-file-segments",        # Сегменты должны быть папками, не файлами
    "no-reserved-folder-names" # Подпапки сегментов не могут называться ui/model/api/lib/config
]

Каждое правило подробно описано в src/pytest_fsd/rules/<rule_name>/README.md.


Настройка Ruff для смежных правил

Для полного покрытия FSD-правил, которые Steiger проверяет на уровне линтинга (и которые pytest-fsd не дублирует), добавьте в pyproject.toml:

[tool.ruff.lint]
select = ["N", "TID"]

[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "parents"
Ruff Plugin Steiger Rule Что проверяет
N (pep8-naming) inconsistent-naming snake_case для модулей, переменных, функций
TID (flake8-tidy-imports) import-locality Запрет relative imports из родительских пакетов

Подробные описания и примеры конфигурации: src/pytest_fsd/rules/inconsistent_naming/README.md и src/pytest_fsd/rules/import_locality/README.md.

Известные ограничения (Known Limitations)

  • TYPE_CHECKING импорты: Правила, использующие pytest-archon (например, forbidden-imports и no-cross-imports), работают на базе динамического анализа графа импортов в рантайме. Импорты, находящиеся внутри блоков if TYPE_CHECKING:, не выполняются при загрузке модуля и, следовательно, не видны для этих правил.
  • Относительные импорты: В модуле ast_utils.py добавлена поддержка относительных путей для проверки no-public-api-sidestep, однако Ruff (плагин TID) всё равно лучше справляется с контролем относительных импортов за пределами слайсов.
  • Динамический __all__: Правило no-public-api-sidestep использует статический AST-анализ для извлечения __all__ из файла __init__.py. Если список экспортов формируется динамически (например, __all__ = a + b), статический анализатор не сможет его прочитать, и инструмент может выдать ложноположительные нарушения. Экспорты в __all__ должны быть заданы как явный список или кортеж.
  • Минимальная версия Python: Библиотека поддерживает Python 3.8+. Для Python <3.11 используется обратная совместимость через пакет tomli, а на Python 3.11+ — встроенный tomllib.

Лицензия

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_fsd-0.2.0.tar.gz (22.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_fsd-0.2.0-py3-none-any.whl (46.2 kB view details)

Uploaded Python 3

File details

Details for the file pytest_fsd-0.2.0.tar.gz.

File metadata

  • Download URL: pytest_fsd-0.2.0.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pytest_fsd-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1ef1ec1e1881f06f787570b4a72c9200820650fd3dad9a1fb27a738507c5a9e0
MD5 2976d6b94b47367f496b9064ae87051a
BLAKE2b-256 340cf7a3e9269833dee9d32bc2f589fed30ccd5d9f8038dedb537873cd32017c

See more details on using hashes here.

File details

Details for the file pytest_fsd-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: pytest_fsd-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 46.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pytest_fsd-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f970b9201f642a56808d174be9b5ad2164bd85de00366c3145a8d52de9b2c3d8
MD5 7477259ce8a70ee735ad77f660107f35
BLAKE2b-256 dc7bf815e6fc5d6e64a4965a00b690adc9458bd43bbbb573e4028f8e6ce1d793

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page