Code Mining. Могут ли аналитики читать код?
Привет, Хабр! На связи участник профессионального сообщества NTA Губин Никита.
Введение
Code mining — это процесс анализа и извлечения информации из исходного кода для получения полезных данных. Аналитики, имея базовые компетенции в разработке, могут использовать их как дополнительный источник информации для улучшения процессов. Инструмент, о котором я расскажу в посте, разделяет код на логические блоки, что позволит улучшить взаимодействие DS‑специалистов и аналитиков.
Аналитики и код
Почему же аналитикам трудно самостоятельно анализировать исходный код?
Выделим несколько причин:
— Незнакомые средства, в виде расширенного поиска по составам репозиториев;
— Непривычное разрозненное расположение информации, которая распределена по умозрительным и непонятным для аналитика признакам;
— Возможное несоответствие документации с исходным кодом.
Решение
В качестве решения было разработано приложение, которое парсит все файлы проекта с кодом в один excel файл, поделенный на логические блоки:
Пример работы
Преимущество данного решения:
— Привычный инструмент. Excel — один из основных инструментов аналитика;
— Код проекта, состоящий из нескольких файлов, собирается в одном месте;
— За счет структуры файла, у аналитика появляются широкие возможности по фильтрации, анализу и поиску необходимой информации.
Реализация
Код написан на Python и предназначен для разбора кода так же на Python.
В посте будут разобраны ключевые моменты. Полный код доступен по ссылке на Github:
https://github.com/AIKarasu/PyCodeToExcel/blob/main/MainCode.
Изначально, необходимо собрать файлы (.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 файл:
Результат разбора
На рисунке выше можно увидеть, какие переменные используются при работе и как они преобразовываются. А за счет фильтров можно отобрать только необходимую в данный момент информацию:
Фильтр по переменной Age
Вывод
Данная программа позволила привлечь к проверке исходного кода специалистов, ранее не сталкивающихся с подобными задачами. Полученная обратная связь была позитивной и, сейчас, система проходит активную стадию тестирования.
Очевидно, что это не конечный продукт и на основе обратной связи будут дорабатываться и внедряться различные методы визуализации и обработки данных. Например, на основе графов.
Но уже сейчас, можно дать ответ на вопрос из темы поста. Да, аналитики могут читать код. И основа, заложенная в тему данного поста, является тому подтверждением.