Skip to content

ak4code/deadcode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dc — поиск мертвого кода в Django проектах

CI

dc это высокопроизводительная утилита на Rust для статического анализа проектов на Python и Django. Главная цель инструмента это точное обнаружение неиспользуемого кода с минимумом ложных срабатываний: анализатор учитывает специфику фреймворка Django и динамическую природу Python.

Установка

Если rust и cargo не установлены:

curl https://sh.rustup.rs -sSf | sh

Установка самого инструмента:

cargo install --git https://github.com/ak4code/deadcode

Запуск

dc            # запуск в корне анализируемого проекта
dc --target-path /path/to/project --verbose
dc --format json > report.json
dc --kind function,method   # только функции и методы

Параметры командной строки:

Параметр По умолчанию Назначение
-t, --target-path . Корневая директория проекта
-c, --config-path автопоиск Путь к файлу конфигурации
-f, --format text Формат отчета: text или json
-k, --kind все виды Фильтр находок: function, class, method, variable; повторение или перечисление через запятую
-v, --verbose выкл. Вывод статистики анализа

Коды завершения (для интеграции с CI):

Код Значение
0 Мертвый код не найден
1 Найден мертвый код
2 Ошибка конфигурации или запуска

Предупреждения о пропущенных файлах (ошибки чтения или парсинга) выводятся в поток ошибок и не прерывают анализ.

Конфигурация

Источники конфигурации в порядке приоритета: явный --config-path, файл .dc.toml в корне проекта, секция [tool.dc] в pyproject.toml. Незнакомые ключи считаются ошибкой — опечатка не отключит настройку молча.

По умолчанию из анализа полностью исключаются .venv (включая окружения uv), migrations и скрытые директории; правила .gitignore учитываются автоматически. Тестовые файлы (пакет tests, а также test_*.py, *_test.py, tests.py, conftest.py) не исключаются, а анализируются только как источник ссылок: код, используемый исключительно в тестах, не считается мертвым, но сами тесты в отчет не попадают. Чтобы исключить тесты полностью, добавьте tests в exclude_directories.

# .dc.toml (или те же ключи в [tool.dc] файла pyproject.toml)

# Директории, исключаемые из анализа.
exclude_directories = [".venv", "migrations", "tests", "node_modules"]

# Дополнительные декораторы точек входа: полное имя или последний сегмент.
extra_entry_point_decorators = ["broker.subscribe", "periodic_task"]

# Имена, всегда считающиеся используемыми (подавление ложных срабатываний).
extra_dynamic_names = ["called_from_template"]

# Дополнительные маркеры базовых классов под управлением фреймворка:
# методы наследников таких баз не считаются мертвым кодом.
extra_framework_base_markers = ["Repository", "Actor"]

Алгоритм анализа

  1. Сбор файлов — обход дерева каталогов (ignore) с фильтрацией .py.
  2. Парсинг — параллельная обработка файлов (rayon + tree-sitter); парсер создается один раз на рабочий поток.
  3. Извлечение сущностей — функции, классы, методы, переменные модулей.
  4. Построение графа — ориентированный граф зависимостей (petgraph) по ссылкам на имена.
  5. Достижимость — обход графа от точек входа; недостижимые узлы попадают в отчет как мертвый код.

Эвристики Django и динамического Python

  • Строковые ссылки — строки из getattr, setattr, hasattr, delattr и importlib.import_module образуют пул динамических ссылок; совпадающие по имени сущности считаются используемыми.
  • Точечные строковые пути — любая строка вида app.views.handler (не менее двух сегментов, каждый — корректный идентификатор Python) считается ссылкой на код и добавляется в пул динамических ссылок. Это покрывает повсеместные для Django строковые ссылки: handler404, значения настроек DRF (EXCEPTION_HANDLER, DEFAULT_SCHEMA_CLASS), строковые константы динамических импортов. Версии (1.2.3), пути файлов и человекочитаемый текст ссылками не считаются.
  • Тесты как источник ссылок — тестовые файлы анализируются ради ссылок на код проекта, поэтому функции, вызываемые только из тестов, не считаются мертвыми; сущности самих тестов в отчет не попадают.
  • Маршрутизация — представления из вызовов path, re_path, url (включая строковые ссылки myapp.views.my_view) помечаются точками входа.
  • Админка — строковые значения list_display, list_filter, actions, readonly_fields классов admin.ModelAdmin добавляются в пул ссылок; классы под @admin.register считаются точками входа.
  • Сигналы и задачи — декораторы receiver, shared_task, task помечают функции точками входа; signal.connect создает связь в графе.
  • Management команды и теги — классы Command в management/commands и функции с register.simple_tag / register.filter это точки входа.
  • Pytestpytest.fixture помечает фикстуры точками входа, строки из pytest.mark.usefixtures добавляются в пул динамических ссылок.
  • Соглашения Djangourlpatterns, модули settings, классы Meta и AppConfig, неявно вызываемые методы (handle, save, validate и другие) и dunder-методы не считаются мертвым кодом.
  • Хуки фреймворков — методы с префиксами validate_, clean_, get_, perform_, has_, test_ вызываются Django, DRF и Pytest по соглашению и не считаются мертвым кодом.
  • Свойства — методы под @property, @cached_property и аксессорами @имя.setter / @имя.getter / @имя.deleter читаются как атрибуты (в том числе из шаблонов Django) и не считаются мертвым кодом.
  • Классы под управлением фреймворка — методы классов, унаследованных от баз Serializer, ViewSet, View, Permission, Form, Admin, Middleware, TestCase, BaseModel (pydantic), Document (elasticsearch-dsl) и подобных, вызываются фреймворком по контракту; признак распространяется по иерархии наследования внутри проекта, поэтому переопределения методов в наследниках не считаются мертвым кодом. Список маркеров расширяется через extra_framework_base_markers. Функции test_* это точки входа Pytest.
  • Вложенные классы соглашенийMeta, Media (Django), Config (pydantic), Index, Django (django-elasticsearch-dsl) читаются фреймворками и не считаются мертвым кодом; методы prepare_* документов вызываются при индексации, классы под @registry.register_document это точки входа.

Архитектура

Кодовая база разделена на четыре слоя с минимальной публичной поверхностью:

src/
├── main.rs              # CLI-оболочка: аргументы, коды завершения
├── lib.rs               # публичный API библиотеки
├── model.rs             # доменные типы: сущности, ссылки, отчеты
├── config.rs            # загрузка и валидация конфигурации
├── error.rs             # типы ошибок
├── heuristics.rs        # эвристики Python / Django / Pytest
├── render.rs            # текстовый и JSON отчеты
└── pipeline/            # конвейер анализа (приватный модуль)
    ├── mod.rs           #   оркестрация run_analysis
    ├── collect.rs       #   этап 1: сбор файлов
    ├── extract.rs       #   этапы 2–3: парсинг и извлечение
    └── reachability.rs  #   этапы 4–5: граф и достижимость

Принципы:

  • ошибки конфигурации фатальны и явно сообщаются; ошибки отдельных файлов накапливаются и не прерывают анализ;
  • результат детерминирован: файлы и находки отсортированы;
  • в коде запрещен unsafe, публичный API полностью документирован (missing_docs включен как warning уровня crate).

Разработка

cargo test                                  # модульные и интеграционные тесты
cargo clippy --all-targets -- -D warnings   # статический анализ
cargo fmt --all --check                     # проверка форматирования

Интеграционные тесты используют демонстрационный Django проект в tests/fixtures/demo_project и проверяют CLI через собранный бинарный файл, включая коды завершения и JSON-вывод.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages