
Привет, Хабр! На связи участник профессионального сообщества NTA Губин Никита.
Введение
Code mining — это процесс анализа и извлечения информации из исходного кода для получения полезных данных. Аналитики, имея базовые компетенции в разработке, могут использовать их как дополнительный источник информации для улучшения процессов. Инструмент, о котором я расскажу в посте, разделяет код на логические блоки, что позволит улучшить взаимодействие DS‑специалистов и аналитиков.
Аналитики и код
Почему же аналитикам трудно самостоятельно анализировать исходный код?
Выделим несколько причин:
Незнакомые средства, в виде расширенного поиска по составам репозиториев;
Непривычное разрозненное расположение информации, которая распределена по умозрительным и непонятным для аналитика признакам;
Возможное несоответствие документации с исходным кодом.
Решение
В качестве решения было разработано приложение, которое парсит все файлы проекта с кодом в один excel файл, поделенный на логические блоки:

Преимущество данного решения:
Привычный инструмент. Excel — один из основных инструментов аналитика;
Код проекта, состоящий из нескольких файлов, собирается в одном месте;
За счет структуры файла, у аналитика появляются широкие возможности по фильтрации, анализу и поиску необходимой информации.
Реализация
Код написан на Python и предназначен для разбора кода так же на Python.
В посте будут разобраны ключевые моменты. Полный код доступен по ссылке на Github.
Изначально, необходимо собрать файлы (.py), которые в дальнейшем будем обрабатывать:
#Метод выгрузки данных def folder(fold,pth,filenames): if fold == True: filenames = glob(os.path.join(pth, "*.py")) elif fold == False: for root, dirs, files in os.walk(pth): files = [f for f in files if not f[0] == '.'] dirs[:] = [d for d in dirs if not d[0] == '.'] for file in files: if(file.endswith(".py")): filenames.append(os.path.join(root,file)) return filenames
Предусмотрено 2 варианта сбора:
Только из указанной папки;
Из указанной папки и всех подпапок (кроме скрытых).
Задаем DataFrame со структурой будущего excel файла:
# Создаем DataFrame с соответствующими колонками col = ['Стратегия', 'Путь', 'Исходная функция', 'Номер строки фрагмента', 'Тип фрагмента', 'Фрагмент'] df = pd.DataFrame(columns=col)
Построчно обрабатываем файлы:
for i in my_code: counter += 1 # Обрабатываем строку i = i.strip(' ') # Проверка для записи исходной строки if 'def ' not in i: ish += i # Обрабатываем комментарии if i[0] == '#': if per != '': perem() # Заполняем IF не в одну строку if y == 1: df.at[row_in_dataframe, 'Стратегия'] = strategy df.at[row_in_dataframe, 'Путь'] = path df.at[row_in_dataframe, 'Номер строки фрагмента'] = counter df.at[row_in_dataframe, 'Тип фрагмента'] = 'Условие IF' df.at[row_in_dataframe, 'Фрагмент'] = usl row_in_dataframe += 1 usl = '' y = 0 dfwrite('Комментарий') # Обрабатываем пустые строки elif i.strip('\n') == '': continue
Python обладает четкой структурой, поэтому, каждая строка проверяется на условия:
# Обрабатываем переменные elif ('=' in i) and (('if ' or 'else' or 'elif ') not in i): y = 0 p = 1 per += i counterP=counter elif (p == 1) and (('if ' or 'else' or 'elif ') not in i): per += i # Обрабатываем IF с условием в одну строку elif (('if ' or 'else' or 'elif ') in i) and (':' in i): if per != '': perem() if ret != '': reter() dfwrite('Условие If') p = 0
Но если каждую строку просто записывать в DataFrame, то в итоговом результате получим «кашу».
Элементы часто занимают более одной строки, поэтому в коде предусмотрены флаги, для записи однотипных данных в одну запись. Например, когда подряд объявляются несколько переменных:
Отобранные данные записываются в DataFrame:
#Обработка фрагментов def dfwrite(fragm): global row_in_dataframe, strategy, path, counter, i, df df.at[row_in_dataframe,'Стратегия']=strategy df.at[row_in_dataframe,'Путь']=path df.at[row_in_dataframe,'Номер строки фрагмента']=counter df.at[row_in_dataframe,'Тип фрагмента']=fragm df.at[row_in_dataframe,'Фрагмент']=i row_in_dataframe+=1 pass
Полученный результат записываем в Excel или в csv:
#Параметры и формат сохранения def save(df,xl,pthEnd): if xl == True: df.to_excel(os.path.join(pthEnd, "CodeMine_Result.xlsx")) elif xl == False: df.to_csv(os.path.join(pthEnd, "CodeMine_Result.csv"), encoding="windows-1251", sep="~")
Для удобства работы добавим пользовательский интерфейс:
if __name__ == "__main__": root = Tk() root.geometry('600x400') var1 = BooleanVar() var1.set(False) var2 = BooleanVar() var2.set(False) lbl = Label(text="Задайте параметры") lbl.pack() frame1 = Frame(borderwidth=1, relief=SOLID) path_label = Label(frame1,text="Введите путь") path_label.pack(anchor=NW) path_entry = Entry(frame1, width=50) path_entry.pack(anchor=NW) open_button = Button(frame1,text="Открыть проводник", command=open_dir1) open_button.pack(anchor=NW) frame1.pack(anchor=NW, fill=X, padx=5, pady=5 )

Путь до обрабатываемых папок выбираем через проводник:
def open_dir1(): global path_entry,filepath1 path_entry.delete(0, END) filepath1 = filedialog.askdirectory() path_entry.insert(0,filepath1)
А после выполнения программы предлагаем открыть результат:
# Сохраняем полученный DataFrame save(df, xl, pthEnd) resultMess = askyesno(title="Разбор выполнен успешно", message="Открыть полученный файл?") if resultMess == True: if xl == True: os.startfile(os.path.join(pthEnd, "CodeMine_Result.xlsx")) else: os.startfile(os.path.join(pthEnd, "CodeMine_Result.csv"))

Давайте рассмотрим применение программы на примере:

Результатом разбора данного фрагмента будет excel файл:

На рисунке выше можно увидеть, какие переменные используются при работе и как они преобразовываются. А за счет фильтров можно отобрать только необходимую в данный момент информацию:

Вывод
Данная программа позволила привлечь к проверке исходного кода специалистов, ранее не сталкивающихся с подобными задачами. Полученная обратная связь была позитивной и, сейчас, система проходит активную стадию тестирования.
Очевидно, что это не конечный продукт и на основе обратной связи будут дорабатываться и внедряться различные методы визуализации и обработки данных. Например, на основе графов.
Но уже сейчас, можно дать ответ на вопрос из темы поста. Да, аналитики могут читать код. И основа, заложенная в тему данного поста, является тому подтверждением.
