Skip to content

Commit fd8c8eb

Browse files
Update
1 parent 1f550fa commit fd8c8eb

File tree

3 files changed

+129
-48
lines changed

3 files changed

+129
-48
lines changed

main.py

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import ast
1616
from stats_window import open_stats_window, analyze_project_structure, parse_python_files
1717

18-
from utils import read_gitignore, is_ignored
18+
from utils import read_gitignore, is_ignored, find_projects
1919

2020
init(autoreset=True)
2121
stop_event = Event()
@@ -24,15 +24,29 @@
2424
imports_count = {}
2525
task_queue = queue.Queue()
2626

27+
# Глобальная переменная для хранения данных о проектах
28+
project_data = {}
29+
project_data_ready = False
2730

31+
import os
32+
33+
# Получаем путь к директории исполняемого файла
34+
script_dir = os.path.dirname(os.path.abspath(__file__))
35+
# Определяем путь к проектам относительно директории исполняемого файла
36+
default_project_path = os.path.join(script_dir)
37+
38+
# Выводим путь для проверки
39+
print(f"Путь к папке projects: {default_project_path}")
40+
41+
# Проверка, существует ли эта директория
42+
if not os.path.isdir(default_project_path):
43+
raise FileNotFoundError(f"Директория 'projects' не найдена по пути: {default_project_path}")
2844

2945

3046
# =========================
3147
# Функции для анализа файлов
3248
# =========================
3349

34-
35-
3650
def get_gitignore_excluded_dirs(gitignore_path='.gitignore'):
3751
excluded_dirs = []
3852
try:
@@ -86,7 +100,7 @@ def find_imports_in_file(file_path):
86100

87101

88102
def scan_directory_for_imports_parallel(directory, progress_label, output_text,task_queue, stop_event):
89-
global imports_count, total_imports
103+
global imports_count, total_imports, project_data
90104

91105
ignored_paths = read_gitignore(directory)
92106
all_imports = []
@@ -136,10 +150,43 @@ def process_file(file_path):
136150
progress_label.config(text="Анализ структуры проекта...")
137151
progress_label.update()
138152
# После анализа импортов
153+
139154
analyze_project_structure(directory, task_queue)
140155

141156

142157

158+
# Вставляем данные в вывод, если необходимо
159+
output_text.insert("end", f"Проектные данные: {project_data}")
160+
output_text.update()
161+
162+
try:
163+
# Сканируем директории и отбираем папки для анализа
164+
projects = find_projects(directory)
165+
166+
# Проводим анализ каждого проекта
167+
project_info = parse_python_files(directory)
168+
project_data = list(project_info.values())
169+
170+
# Переименование поля
171+
for item in project_data:
172+
item['date'] = item.pop('created')
173+
174+
project_data_ready = True
175+
176+
formatted_data = "\n".join(
177+
[f"Проект: {project}\n"
178+
f" Кол-во .py: {data['py_count']}\n"
179+
f" Библиотеки: {', '.join(data['libs'])}\n"
180+
f" Создан: {data['date']}\n"
181+
f" Директории: {', '.join(data['dirs'])}\n"
182+
for project, data in project_info.items()]
183+
)
184+
185+
output_text.insert("end", f"\nПроектные данные:\n{formatted_data}")
186+
output_text.update()
187+
188+
except Exception as e:
189+
task_queue.put(f"Ошибка при анализе структуры проектов: {e}")
143190

144191
# =========================
145192
# Работа с интерфейсом
@@ -351,13 +398,11 @@ def on_closing():
351398
btn_others = Button(lib_frame, text="Показать прочие библиотеки", command=lambda: show_others(imports_count, total_imports, output_text))
352399
btn_others.pack(side="left", padx=10)
353400

354-
# Получаем данные о проектах для анализа
355-
default_project_path = "E:/Code/PYTHON/projects" # <-- путь к проектам
356-
project_data = list(parse_python_files(default_project_path).values())
357-
358401

359402
# Новая кнопка: временной анализ проектов
403+
# btn_stats_by_date = Button(lib_frame, text="Анализ проектов по дате", command=lambda: open_stats_window(window, project_data) )
360404
btn_stats_by_date = Button(lib_frame, text="Анализ проектов по дате", command=lambda: open_stats_window(window, project_data) )
405+
361406
btn_stats_by_date.pack(side="left", padx=10)
362407

363408

stats_window.py

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import ast
99
import datetime
1010

11-
from utils import read_gitignore, is_ignored
11+
from utils import read_gitignore, is_ignored, find_projects
12+
1213

1314
def analyze_project_structure(directory, task_queue):
1415
ignored_paths = read_gitignore(directory)
@@ -48,12 +49,15 @@ def analyze_project_structure(directory, task_queue):
4849

4950

5051

51-
"""
52+
5253
def parse_python_files(projects_dir):
5354
project_stats = {}
5455

55-
for root, dirs, files in os.walk(projects_dir):
56-
project_name = os.path.relpath(root, projects_dir).split(os.sep)[0]
56+
# Используем find_projects для поиска папок с проектами
57+
projects = find_projects(projects_dir)
58+
59+
for project_dir in projects:
60+
project_name = os.path.relpath(project_dir, projects_dir).split(os.sep)[0]
5761

5862
if project_name not in project_stats:
5963
project_stats[project_name] = {
@@ -63,40 +67,42 @@ def parse_python_files(projects_dir):
6367
"dirs": set()
6468
}
6569

66-
for file in files:
67-
if file.endswith(".py"):
68-
file_path = os.path.join(root, file)
69-
70-
# Обновляем счётчик Python файлов
71-
project_stats[project_name]["py_count"] += 1
72-
73-
# Обновляем дату создания проекта
74-
creation_time = os.path.getctime(file_path)
75-
creation_date = datetime.datetime.fromtimestamp(creation_time)
76-
77-
current_created = project_stats[project_name]["created"]
78-
if current_created is None or creation_date < current_created:
79-
project_stats[project_name]["created"] = creation_date
80-
81-
# Сбор директорий
82-
rel_dir = os.path.relpath(root, os.path.join(projects_dir, project_name))
83-
if rel_dir != ".":
84-
project_stats[project_name]["dirs"].add(rel_dir)
85-
86-
# Парсим файл для библиотек
87-
try:
88-
with open(file_path, "r", encoding="utf-8") as f:
89-
node = ast.parse(f.read(), filename=file_path)
90-
91-
for sub_node in ast.walk(node):
92-
if isinstance(sub_node, ast.Import):
93-
for alias in sub_node.names:
94-
project_stats[project_name]["libs"].add(alias.name.split('.')[0])
95-
elif isinstance(sub_node, ast.ImportFrom):
96-
if sub_node.module:
97-
project_stats[project_name]["libs"].add(sub_node.module.split('.')[0])
98-
except Exception:
99-
continue
70+
# Склонение директорий с проектами
71+
for root, dirs, files in os.walk(project_dir):
72+
for file in files:
73+
if file.endswith(".py"):
74+
file_path = os.path.join(root, file)
75+
76+
# Обновляем счётчик Python файлов
77+
project_stats[project_name]["py_count"] += 1
78+
79+
# Обновляем дату создания проекта
80+
creation_time = os.path.getctime(file_path)
81+
creation_date = datetime.datetime.fromtimestamp(creation_time)
82+
83+
current_created = project_stats[project_name]["created"]
84+
if current_created is None or creation_date < current_created:
85+
project_stats[project_name]["created"] = creation_date
86+
87+
# Сбор директорий
88+
rel_dir = os.path.relpath(root, os.path.join(projects_dir, project_name))
89+
if rel_dir != ".":
90+
project_stats[project_name]["dirs"].add(rel_dir)
91+
92+
# Парсим файл для библиотек
93+
try:
94+
with open(file_path, "r", encoding="utf-8") as f:
95+
node = ast.parse(f.read(), filename=file_path)
96+
97+
for sub_node in ast.walk(node):
98+
if isinstance(sub_node, ast.Import):
99+
for alias in sub_node.names:
100+
project_stats[project_name]["libs"].add(alias.name.split('.')[0])
101+
elif isinstance(sub_node, ast.ImportFrom):
102+
if sub_node.module:
103+
project_stats[project_name]["libs"].add(sub_node.module.split('.')[0])
104+
except Exception:
105+
continue
100106

101107
# Приведение к нужному формату
102108
for proj in project_stats:
@@ -106,20 +112,30 @@ def parse_python_files(projects_dir):
106112
project_stats[proj]["created"] = project_stats[proj]["created"].strftime("%Y-%m-%d %H:%M:%S")
107113

108114
return project_stats
109-
"""
110115

111116

112117
def open_stats_window(root, project_data: list[dict]):
113118
stats_win = tk.Toplevel(root)
114119
stats_win.title("Статистика проектов")
115120
stats_win.geometry("800x600")
116121

122+
# Проверка наличия данных в project_data
123+
if not project_data:
124+
tk.Label(stats_win, text="Нет данных для отображения статистики.").pack(pady=20)
125+
return
126+
117127
df = pd.DataFrame(project_data)
128+
129+
# Если данных в столбце 'date' нет, выводим сообщение
118130
if df.empty or 'date' not in df.columns:
119131
tk.Label(stats_win, text="Недостаточно данных для отображения статистики.").pack(pady=20)
120132
return
121133

122-
df['date'] = pd.to_datetime(df['date'])
134+
# Конвертируем 'date' в формат datetime для графиков
135+
df['date'] = pd.to_datetime(df['date'], errors='coerce')
136+
137+
# Убираем записи с некорректными датами
138+
df = df.dropna(subset=['date'])
123139

124140
stats_canvas = tk.Frame(stats_win)
125141
stats_canvas.pack(fill="both", expand=True)

utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
import os
22

3+
# =========================
4+
# Функции для анализа файлов
5+
# =========================
6+
7+
def find_projects(root_dir):
8+
projects = []
9+
visited = set()
10+
11+
for root, dirs, files in os.walk(root_dir):
12+
# Пропустить уже отмеченные как проекты папки
13+
if any(root.startswith(p) for p in visited):
14+
continue
15+
16+
# Если есть хотя бы один .py файл — это проект
17+
if any(f.endswith('.py') for f in files):
18+
projects.append(root)
19+
visited.add(root)
20+
21+
return projects
22+
323

424
def read_gitignore(directory):
525
gitignore_path = os.path.join(directory, '.gitignore')

0 commit comments

Comments
 (0)