Цей проєкт збирає та аналізує метрики об'єктно-орієнтованого коду з Python-репозиторіїв, пов'язаних зі штучним інтелектом (ML/DL/NLP/CV/LLM).
Всі метрикиділяться на дві групи:
- Кількість рядків коду (KLOC)
- Кількість класів
- Середня кількість методів у класі
- Глибина дерева наслідування (середня)
- Кількість відносин між класами (оцінка)
- RFC — Response For a Class
- CBO — Coupling Between Objects
- WMC — Weighted Methods per Class
Формула:
KLOC = Кількість рядків коду / 1000
Як рахується:
- Використовується
cloc
(якщо є) або ручний підрахунок всіх непорожніх рядків у.py
файлах - Виключаються директорії:
tests
,docs
,examples
,build
,dist
,venv
, тощо - Результат — значення в тисячах рядків (KLOC)
Формула:
Nс = кількість конструкцій class у коді
Як рахується:
- Парсер
ast
Python обходить всі файли - Кожен вузол
ast.ClassDef
враховується як окремий клас
Формула:
M̄с = (Σ Mᵢ) / Nс
де Mᵢ
— кількість методів (функцій) у класі i
Як рахується:
- Для кожного класу підраховуються внутрішні
FunctionDef
абоAsyncFunctionDef
- Береться середня кількість методів на клас
Формула для одного класу:
DIT(C) = довжина найдовшого ланцюга наслідування від класу C
Середнє значення:
DIT̄ = (1/Nс) × Σ DIT(Cᵢ)
Як рахується:
- Для кожного класу беруться його базові класи (
bases
вast.ClassDef
) - Якщо базові класи також визначені в проєкті — продовжуємо по ланцюгу
- DIT збільшується на 1 за кожен рівень наслідування
- Середнє значення по всіх класах — середня глибина дерева
Приклад:
class A: pass
class B(A): pass
class C(B): pass
DIT(A) = 0
DIT(B) = 1
DIT(C) = 2
Формула:
R = |Eінheritance ∪ Eusage|
де:
Eінheritance
— множина ребер "A → B" (A наслідує B)Eusage
— множина ребер "A → B" (A використовує B)
Як рахується:
- Якщо клас наслідує інший (по
bases
), додається зв'язок - Якщо клас використовує інший клас (згадування імені іншого класу в атрибутах або викликах), також додається зв'язок
- Рахується кількість унікальних пар (клас A → клас B)
Ідея: Скільки потенційних «реакцій» (методів) може викликати об'єкт даного класу при запиті.
Формула:
RFC(C) = |M| + |R|
де:
M
— кількість методів у класіR
— кількість унікальних викликів методів з цього класу (усіх функцій, викликаних усередині методів)
Як рахується:
- Збираємо всі
FunctionDef
всередині класу - Проходимо по тілу кожного методу, знаходимо всі
ast.Call
RFC = кількість власних методів + кількість унікальних викликів
Інтерпретація:
- Чим вище RFC — тим складніше зрозуміти поведінку класу при виклику (висока відповідальність)
- Високе значення RFC вказує на складність тестування та підтримки
Ідея: Кількість унікальних зовнішніх класів, з якими даний клас пов'язаний (використовує, імпортує, викликає тощо).
Формула (апроксимація):
CBO(C) = |(Rcamel ∪ Rknown) − {C}|
де:
Rcamel
— множина всіх CamelCase ідентифікаторів (схожих на імена класів)Rknown
— множина імен інших класів, визначених в цьому ж проєкті{C}
— сам клас (виключається)
Як рахується:
- Для кожного класу аналізуються всі імена (
ast.Name
,ast.Attribute
) - Якщо ідентифікатор схожий на назву класу (CamelCase) або співпадає з іншим класом проєкту — вважається зв'язком
- Підрахунок унікальних імен
Інтерпретація:
- Висока зв'язаність (високий CBO) ускладнює тестування та повторне використання
- Низький CBO вказує на слабку залежність між класами (добре для модульності)
Ідея: Сумарна складність методів класу.
Формула:
WMC(C) = Σ CCᵢ
де:
M
— кількість методів у класіCCᵢ
— цикломатична складність методуi
Як рахується:
- Використовується бібліотека
radon
, яка обчислює Cyclomatic Complexity (CC) кожного методу - Якщо
radon
недоступний — беретьсяCCᵢ = 1
WMC = сума CC по всіх методах класу
Інтерпретація:
- Чим вище WMC — тим складніше тестувати та супроводжувати клас
WMC > 50
зазвичай сигнал про надмірну складність
Цикломатична складність (CC):
- CC вимірює кількість незалежних шляхів виконання через код
- Враховує умови (
if
,elif
,else
), цикли (for
,while
), винятки (try/except
) CC = 1
для простої функції без розгалужень
Після обчислення всіх метрик для кожного класу в проєкті береться середнє значення по класах:
Метрика | Символ | Опис |
---|---|---|
Середня кількість методів у класі | M̄с | Просте середнє |
Глибина дерева наслідування (середня) | DIT̄ | Середня глибина ланцюга |
RFC (середнє) | RFC̄ | Середній RFC по всіх класах |
CBO (середнє) | CBŌ | Середній coupling |
WMC (середнє) | WMC̄ | Середня сумарна складність методів |
Категорія | Метрика | Символ | Формула | Коментар |
---|---|---|---|---|
По розміру | Кількість рядків коду | KLOC | LOC / 1000 | Кількість непорожніх рядків |
Кількість класів | Nс | — | AST ClassDef | |
Середня кількість методів | M̄с | ΣMᵢ / Nс | Методи в класах | |
Глибина наслідування | DIT̄ | ΣDIT(Cᵢ) / Nс | Ланцюги наслідування | |
Відносини між класами | R | |Eінheritance ∪ Eusage| | Наслідування + використання | |
По якості та складності | RFC | RFC(C) | |M| + |R| | Відповідь класу |
CBO | CBO(C) | |Rcamel ∪ Rknown| | Зв'язаність об'єктів | |
WMC | WMC(C) | ΣCCᵢ | Вага методів (цикломатика) |
Використовується GitHub Search API з наступними критеріями:
- Мова: Python
- Теми:
machine-learning
,deep-learning
,nlp
,llm
,computer-vision
- Мінімальна кількість зірок: 300 (за замовчуванням)
- Виключаються форки
- Використовується
shallow clone
(--depth 1
) для економії місця - Репозиторії зберігаються у
work_ai_metrics/repos/
Двопрохідний аналіз:
-
Перший прохід: збір всіх класів та їх базових класів
- Парсинг всіх
.py
файлів черезast
- Збір імен класів та їх
bases
- Парсинг всіх
-
Другий прохід: підрахунок метрик для кожного класу
- Аналіз методів
- Підрахунок цикломатичної складності (через
radon
) - Виявлення викликів та залежностей
- Побудова графу відносин
З аналізу виключаються файли з директорій:
venv
,.venv
,site-packages
tests
,test
docs
,examples
build
,dist
node_modules
.git
,__pycache__
pip install requests radon
Опціонально (для точного підрахунку LOC):
# cloc - https://github.com/AlDanial/cloc
# macOS:
brew install cloc
# Linux:
sudo apt-get install cloc
# Базове використання
python collect_ai_python_metrics.py
# З налаштуваннями
python collect_ai_python_metrics.py \
--limit 100 \
--min-stars 500 \
--out результати.csv \
--workdir робоча_директорія
# Аналіз без клонування (використовувати існуючі репозиторії)
python collect_ai_python_metrics.py --no-clone
Параметр | Опис | За замовчуванням |
---|---|---|
--limit |
Кількість репозиторіїв для збору | 50 |
--min-stars |
Мінімальна кількість зірок на GitHub | 300 |
--out |
Файл для збереження результатів | results.csv |
--workdir |
Робоча директорія | work_ai_metrics |
--no-clone |
Аналізувати існуючі репозиторії без клонування | — |
Для збільшення ліміту API-запитів:
export GITHUB_TOKEN="ваш_токен"
CSV-файл з UTF-8 BOM кодуванням, колонки:
- Назва проєкту
- Посилання
- Кількість рядків коду (тис.)
- Кількість класів
- Середня кількість методів у класі
- Глибина дерева наслідування (середня)
- Кількість відносин між класами (оцінка)
- RFC (середнє)
- CBO (середнє)
- WMC (середнє)
Використовується вбудований модуль ast
Python для статичного аналізу коду:
- Виявлення класів:
ast.ClassDef
- Виявлення методів:
ast.FunctionDef
,ast.AsyncFunctionDef
- Виявлення викликів:
ast.Call
- Виявлення посилань:
ast.Name
,ast.Attribute
Обчислюється за допомогою бібліотеки radon:
- Аналізує структуру коду (умови, цикли, винятки)
- Повертає числове значення складності для кожної функції/методу
- Fallback: якщо
radon
недоступний — використовуєтьсяCC = 1
для кожного методу
Будується граф відносин між класами:
- Вершини: класи проєкту
- Ребра: відносини наслідування та використання
- Підраховується загальна кількість унікальних ребер
- CK Metrics: Chidamber & Kemerer (1994) — класичні об'єктно-орієнтовані метрики
- Radon: https://radon.readthedocs.io/ — бібліотека для розрахунку метрик коду
- cloc: https://github.com/AlDanial/cloc — підрахунок рядків коду