Coders Packet

Software Refactoring using python Tkinter and astor

By J Suhasini

Software refactoring is a technique for improving the design and structure of existing code, without changing its functionality.

DESCRIPTION OF SOFTWARE REFACTORING PROJECT:

Refactoring aims to make the code more maintainable, readable, and extendable. It is a process that helps to identify and remove code smells and improves the overall quality of the software. The main objective of software refactoring is to detect the variables defined but not used anywhere,
second, it is used to detect the unnecessary defined methods, third to detect the number of lines in the code.

Using the Python programming language, a compiler is created that refactors code on variables. Software refactoring is the process of improving an element of code's underlying structure without changing its external performance. There are a number of typical techniques you may utilise when refactoring variables:

1. Rename: One of the basic refactoring approaches is variable renaming, which is done to make a variable's usage or intent more obvious

2. Extract Variable: You can extract an expression into a distinct variable if it is a part of a long line of code or a complicated expression that depends on        the variable. By doing this, you may reuse the value in different situations in addition to enhancing it easier to understand.

3. Encapsulate Variable: If you want to restrict access to variables that are being accessed directly from numerous locations or subsequently add new            functionality to them, create getter and setter methods to encapsulate such variables

4. Replace Magic Numbers with Constants: If your code has a number of separated numerical values, constants can be made use of in place of magic            numbers.

5. Introduce Explaining Variable: For the purpose of to divide up large or challenging-to-understand phrases into smaller, simpler to understand sections,
    intermediate variables with appropriate names can be generated. This makes the intent of the code more clear and makes it simpler for people to            grasp.

6. Inline Variable: Using an inline variable can be useful when a variable no longer serves a clear function or benefits the code.

Enhancing the maintainability, readability, and general quality of the code is the major goal of refactoring.

SOURCE CODE:

from tkinter import *
from tkinter.filedialog import asksaveasfilename, askopenfilename
import subprocess
import difflib
import ast
import astor
import re

compiler = Tk()
compiler.title('Fantastic IDE')
file_path = ''

def set_file_path(path):
    global file_path
    file_path = path

def open_file():
    path = askopenfilename(filetypes=[('Python Files', '*.py')])
    with open(path, 'r') as file:
        code = file.read()
        editor.delete('1.0', END)
        editor.insert('1.0', code)
        set_file_path(path)

def save_as():
    if file_path == '':
        path = asksaveasfilename(filetypes=[('Python Files', '*.py')])
    else:
        path = file_path
    with open(path, 'w') as file:
        code = editor.get('1.0', END)
        file.write(code)
        set_file_path(path)

def run():
    if file_path == '':
        save_prompt = Toplevel()
        text = Label(save_prompt, text='Please save your code')
        text.pack()
        return
    command = f'python {file_path}'
    process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    output, error = process.communicate()
    code_output.insert('1.0', output)
    code_output.insert('1.0',  error)

def detect_duplicates():
    text = editor.get('1.0', END)
    lines = text.splitlines()
    duplicates = []
    threshold = 0.8
    for i, line1 in enumerate(lines):
        for j, line2 in enumerate(lines[i+1:]):
            ratio = difflib.SequenceMatcher(None, line1, line2).ratio()
            if ratio > threshold:
                duplicates.append((i+1, j+i+2))
    if duplicates:
        code_output.delete('1.0', END)
        code_output.insert('1.0', 'Duplicate lines:\n')
        for i, j in duplicates:
            code_output.insert(END, f'Lines {i} and {j}\n')
    else:
        code_output.delete('1.0', END)
        code_output.insert('1.0', 'No duplicates found\n')

def detect_unused_variables():
    text = editor.get('1.0', END)
    tree = ast.parse(text)
    source = astor.to_source(tree)
    used_variables = set(re.findall(r'\b([A-Za-z_]\w*)\b', source))
    unused_variables = set()

    def visit(node):
        if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store):
            unused_variables.add(node.id)

    for node in ast.walk(tree):
        if isinstance(node, ast.FunctionDef) or isinstance(node, ast.ClassDef):
            for arg in node.args.args:
                used_variables.add(arg.arg)
        visit(node)

    unused_variables -= used_variables

    if unused_variables:
        code_output.delete('1.0', END)
        code_output.insert('1.0', 'Unused variables:\n')
        for variable in unused_variables:
            code_output.insert(END, f'{variable}\n')

        # suggest removing the unused variables
        suggested_code = text
        for variable in unused_variables:
            suggested_code = re.sub(r'\b' + variable + r'\b', '', suggested_code)
        code_output.insert(END, '\nSuggested code:\n')
        code_output.insert(END, suggested_code)

    else:
        code_output.delete('1.0', END)
        code_output.insert('1.0', 'unused variables found\n')

menu_bar = Menu(compiler)

file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label='Open', command=open_file)
file_menu.add_command(label='Save', command=save_as)
file_menu.add_command(label='Save As', command=save_as)
file_menu.add_command(label='Exit', command=exit)
menu_bar.add_cascade(label='File', menu=file_menu)

run_bar = Menu(menu_bar, tearoff=0)
run_bar.add_command(label='Run', command=run)
menu_bar.add_cascade(label='Run', menu=run_bar)

duplicate_menu = Menu(menu_bar, tearoff=0)
duplicate_menu.add_command(label='Detect Duplicates', command=detect_duplicates)
menu_bar.add_cascade(label='Duplicate', menu=duplicate_menu)

unused_menu = Menu(menu_bar, tearoff=0)
unused_menu.add_command(label='Detect Unused Variables', command=detect_unused_variables)
menu_bar.add_cascade(label='Unused', menu=unused_menu)

compiler.config(menu=menu_bar)

editor = Text()
editor.pack()

code_output = Text(height=10)
code_output.pack()

compiler.mainloop()
 

Download Complete Code

Comments

No comments yet

Download Packet

Reviews Report

Submitted by J Suhasini (Suhasini)

Download packets of source code on Coders Packet