patternpythonMinor
Tortoise Helper Program
Viewed 0 times
helperprogramtortoise
Problem
Recently, the following code was written to help automate some processes that are typically executed while working with a Mercurial database. What is shown below is basically a first draft of the program and was quickly written to test out the idea of creating a GUI tool for others to use.
Question: Are there any obvious flaws in how the program works or how the code is formatted and arranged that might be improved for future versions?
```
import sys
import subprocess
import tkFileDialog
import Tkinter
class TortoiseHelper(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.initialize()
self.create_controls()
if len(sys.argv) > 1:
if TortoiseHelper.validate_repo(sys.argv[1]):
self.repoPath.set(sys.argv[1])
self.refresh_repo()
def change_repo(self):
newPath = tkFileDialog.askdirectory(parent=self)
if TortoiseHelper.validate_repo(newPath):
self.repoPath.set(newPath)
self.refresh_repo()
def create_controls(self):
mainFrame = Tkinter.Frame(self)
mainFrame.grid(row=0, column=0, padx=10, pady=10, sticky=(Tkinter.N, Tkinter.E, Tkinter.S, Tkinter.W))
mainFrame.columnconfigure(1, weight=1)
mainFrame.rowconfigure(13, weight=1)
repoLabel = Tkinter.Label(mainFrame)
repoLabel['text'] = 'Repository'
repoLabel.grid(row=0, column=0, sticky=Tkinter.E)
lblRepo = Tkinter.Label(mainFrame)
lblRepo['textvariable'] = self.repoPath
lblRepo['relief'] = Tkinter.SUNKEN
lblRepo['anchor'] = Tkinter.W
lblRepo.grid(row=0, column=1, ipadx=4, pady=2, sticky=(Tkinter.E, Tkinter.W))
btnRefresh = Tkinter.Button(mainFrame)
btnRefresh['text'] = 'Refresh'
btnRefresh['command'] = self.refresh_repo
btnRefresh.grid(row=0, column=2, padx=2)
btnChange = Tkinter.Button(mainFrame)
btnChange['text'] = 'Change'
btnCh
Question: Are there any obvious flaws in how the program works or how the code is formatted and arranged that might be improved for future versions?
```
import sys
import subprocess
import tkFileDialog
import Tkinter
class TortoiseHelper(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.initialize()
self.create_controls()
if len(sys.argv) > 1:
if TortoiseHelper.validate_repo(sys.argv[1]):
self.repoPath.set(sys.argv[1])
self.refresh_repo()
def change_repo(self):
newPath = tkFileDialog.askdirectory(parent=self)
if TortoiseHelper.validate_repo(newPath):
self.repoPath.set(newPath)
self.refresh_repo()
def create_controls(self):
mainFrame = Tkinter.Frame(self)
mainFrame.grid(row=0, column=0, padx=10, pady=10, sticky=(Tkinter.N, Tkinter.E, Tkinter.S, Tkinter.W))
mainFrame.columnconfigure(1, weight=1)
mainFrame.rowconfigure(13, weight=1)
repoLabel = Tkinter.Label(mainFrame)
repoLabel['text'] = 'Repository'
repoLabel.grid(row=0, column=0, sticky=Tkinter.E)
lblRepo = Tkinter.Label(mainFrame)
lblRepo['textvariable'] = self.repoPath
lblRepo['relief'] = Tkinter.SUNKEN
lblRepo['anchor'] = Tkinter.W
lblRepo.grid(row=0, column=1, ipadx=4, pady=2, sticky=(Tkinter.E, Tkinter.W))
btnRefresh = Tkinter.Button(mainFrame)
btnRefresh['text'] = 'Refresh'
btnRefresh['command'] = self.refresh_repo
btnRefresh.grid(row=0, column=2, padx=2)
btnChange = Tkinter.Button(mainFrame)
btnChange['text'] = 'Change'
btnCh
Solution
The code could be redesigned to make porting to Python 3.X easier in the future. A lot of refactoring is needed, and the following is only a partial redesign. The biggest problem that the program still has is how it locks up while trying to complete long-running operations. My recommendation is to take the following code and use at the starting point for an even more detailed rewrite.
```
#! /usr/bin/env python2
# http://codereview.stackexchange.com/questions/144238
from __future__ import division # PEP 238
from __future__ import absolute_import # PEP 328
from __future__ import print_function # PEP 3105
from __future__ import unicode_literals # PEP 3112
import subprocess
import sys
import Tkinter as tkinter
from Tkconstants import *
import tkFileDialog
tkinter.filedialog = tkFileDialog
del tkFileDialog
class TortoiseTool(tkinter.Frame, object):
__DEFAULT = object()
@classmethod
def main(cls, argv=None):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
# Configure the main window.
root.title('Tortoise Helper')
root.wm_minsize(400, 500)
# Create the application with placement.
tool = cls(root, argv=argv)
tool.grid(sticky=NSEW)
# Configure the resizing capabilities.
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()
def __init__(self, master=None, cnf=__DEFAULT, **kw):
argv = kw.pop('argv', None)
super(TortoiseTool, self).__init__(master, self.__eval(cnf, {}), **kw)
# Initialize the variables used with the widgets.
self.repo_path = tkinter.StringVar(self)
self.repo_status = tkinter.StringVar(self)
self.repo_branch = tkinter.StringVar(self)
self.option_commit = tkinter.BooleanVar(self)
self.new_branch_name = tkinter.StringVar(self)
self.option_close = tkinter.BooleanVar(self)
self.option_merge_test = tkinter.BooleanVar(self)
self.option_silent_merge_test = tkinter.BooleanVar(self)
self.option_merge_production = tkinter.BooleanVar(self)
self.option_silent_merge_production = tkinter.BooleanVar(self)
self.option_push = tkinter.BooleanVar(self)
# Create all widgets used in the applications.
self.repo_label = tkinter.Label(self, text='Repository')
self.lbl_repo = tkinter.Label(
self, textvariable=self.repo_path, relief=SUNKEN, anchor=W
)
self.btn_refresh = tkinter.Button(
self, text='Refresh', command=self.refresh_repo
)
self.btn_change = tkinter.Button(
self, text='Change', command=self.change_repo
)
self.status_label = tkinter.Label(self, text='Status')
self.lbl_status = tkinter.Label(
self, textvariable=self.repo_status, relief=SUNKEN, anchor=W,
justify=LEFT
)
self.branch_label = tkinter.Label(self, text='Branch')
self.lbl_branch = tkinter.Label(
self, textvariable=self.repo_branch, relief=SUNKEN, anchor=W
)
self.chk_commit = tkinter.Checkbutton(
self, text='Commit', variable=self.option_commit,
command=self.on_commit_click
)
self.ent_branch_name = tkinter.Entry(
self, textvariable=self.new_branch_name
)
self.branch_name_label = tkinter.Label(self, text='New branch name')
self.commit_message_label = tkinter.Label(self, text='Commit message')
self.txt_commit_message = tkinter.Text(self, height=4)
self.chk_close = tkinter.Checkbutton(
self, text='Close branch', variable=self.option_close
)
self.chk_merge_test = tkinter.Checkbutton(
self, text='Merge with Test', variable=self.option_merge_test,
command=self.on_merge_test_click
)
self.chk_merge_test_silent = tkinter.Checkbutton(
self, text='Attempt silent merge', state=DISABLED,
variable=self.option_silent_merge_test
)
self.chk_merge_production = tkinter.Checkbutton(
self, text='Merge with Production',
variable=self.option_merge_production,
command=self.on_merge_production_click
)
self.chk_merge_production_silent = tkinter.Checkbutton(
self, text='Attempt silent merge', state=DISABLED,
variable=self.option_silent_merge_production
)
self.chk_push = tkinter.Checkbutton(
self, text='Push', variable=self.option_push
)
self.btn_run = tkinter.Button(self, text='Run', command=self.run)
self.btn_cancel = tkinter.Button(
self, text='Cancel', command=self.quit
)
self.txt_output = tkinter.Text(self, state=DISABLED)
# Finish the setup process and configure parameters.
self.grid_all_widgets()
self.adjust_resizing_weights()
```
#! /usr/bin/env python2
# http://codereview.stackexchange.com/questions/144238
from __future__ import division # PEP 238
from __future__ import absolute_import # PEP 328
from __future__ import print_function # PEP 3105
from __future__ import unicode_literals # PEP 3112
import subprocess
import sys
import Tkinter as tkinter
from Tkconstants import *
import tkFileDialog
tkinter.filedialog = tkFileDialog
del tkFileDialog
class TortoiseTool(tkinter.Frame, object):
__DEFAULT = object()
@classmethod
def main(cls, argv=None):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
# Configure the main window.
root.title('Tortoise Helper')
root.wm_minsize(400, 500)
# Create the application with placement.
tool = cls(root, argv=argv)
tool.grid(sticky=NSEW)
# Configure the resizing capabilities.
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()
def __init__(self, master=None, cnf=__DEFAULT, **kw):
argv = kw.pop('argv', None)
super(TortoiseTool, self).__init__(master, self.__eval(cnf, {}), **kw)
# Initialize the variables used with the widgets.
self.repo_path = tkinter.StringVar(self)
self.repo_status = tkinter.StringVar(self)
self.repo_branch = tkinter.StringVar(self)
self.option_commit = tkinter.BooleanVar(self)
self.new_branch_name = tkinter.StringVar(self)
self.option_close = tkinter.BooleanVar(self)
self.option_merge_test = tkinter.BooleanVar(self)
self.option_silent_merge_test = tkinter.BooleanVar(self)
self.option_merge_production = tkinter.BooleanVar(self)
self.option_silent_merge_production = tkinter.BooleanVar(self)
self.option_push = tkinter.BooleanVar(self)
# Create all widgets used in the applications.
self.repo_label = tkinter.Label(self, text='Repository')
self.lbl_repo = tkinter.Label(
self, textvariable=self.repo_path, relief=SUNKEN, anchor=W
)
self.btn_refresh = tkinter.Button(
self, text='Refresh', command=self.refresh_repo
)
self.btn_change = tkinter.Button(
self, text='Change', command=self.change_repo
)
self.status_label = tkinter.Label(self, text='Status')
self.lbl_status = tkinter.Label(
self, textvariable=self.repo_status, relief=SUNKEN, anchor=W,
justify=LEFT
)
self.branch_label = tkinter.Label(self, text='Branch')
self.lbl_branch = tkinter.Label(
self, textvariable=self.repo_branch, relief=SUNKEN, anchor=W
)
self.chk_commit = tkinter.Checkbutton(
self, text='Commit', variable=self.option_commit,
command=self.on_commit_click
)
self.ent_branch_name = tkinter.Entry(
self, textvariable=self.new_branch_name
)
self.branch_name_label = tkinter.Label(self, text='New branch name')
self.commit_message_label = tkinter.Label(self, text='Commit message')
self.txt_commit_message = tkinter.Text(self, height=4)
self.chk_close = tkinter.Checkbutton(
self, text='Close branch', variable=self.option_close
)
self.chk_merge_test = tkinter.Checkbutton(
self, text='Merge with Test', variable=self.option_merge_test,
command=self.on_merge_test_click
)
self.chk_merge_test_silent = tkinter.Checkbutton(
self, text='Attempt silent merge', state=DISABLED,
variable=self.option_silent_merge_test
)
self.chk_merge_production = tkinter.Checkbutton(
self, text='Merge with Production',
variable=self.option_merge_production,
command=self.on_merge_production_click
)
self.chk_merge_production_silent = tkinter.Checkbutton(
self, text='Attempt silent merge', state=DISABLED,
variable=self.option_silent_merge_production
)
self.chk_push = tkinter.Checkbutton(
self, text='Push', variable=self.option_push
)
self.btn_run = tkinter.Button(self, text='Run', command=self.run)
self.btn_cancel = tkinter.Button(
self, text='Cancel', command=self.quit
)
self.txt_output = tkinter.Text(self, state=DISABLED)
# Finish the setup process and configure parameters.
self.grid_all_widgets()
self.adjust_resizing_weights()
Code Snippets
#! /usr/bin/env python2
# http://codereview.stackexchange.com/questions/144238
from __future__ import division # PEP 238
from __future__ import absolute_import # PEP 328
from __future__ import print_function # PEP 3105
from __future__ import unicode_literals # PEP 3112
import subprocess
import sys
import Tkinter as tkinter
from Tkconstants import *
import tkFileDialog
tkinter.filedialog = tkFileDialog
del tkFileDialog
class TortoiseTool(tkinter.Frame, object):
__DEFAULT = object()
@classmethod
def main(cls, argv=None):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
# Configure the main window.
root.title('Tortoise Helper')
root.wm_minsize(400, 500)
# Create the application with placement.
tool = cls(root, argv=argv)
tool.grid(sticky=NSEW)
# Configure the resizing capabilities.
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()
def __init__(self, master=None, cnf=__DEFAULT, **kw):
argv = kw.pop('argv', None)
super(TortoiseTool, self).__init__(master, self.__eval(cnf, {}), **kw)
# Initialize the variables used with the widgets.
self.repo_path = tkinter.StringVar(self)
self.repo_status = tkinter.StringVar(self)
self.repo_branch = tkinter.StringVar(self)
self.option_commit = tkinter.BooleanVar(self)
self.new_branch_name = tkinter.StringVar(self)
self.option_close = tkinter.BooleanVar(self)
self.option_merge_test = tkinter.BooleanVar(self)
self.option_silent_merge_test = tkinter.BooleanVar(self)
self.option_merge_production = tkinter.BooleanVar(self)
self.option_silent_merge_production = tkinter.BooleanVar(self)
self.option_push = tkinter.BooleanVar(self)
# Create all widgets used in the applications.
self.repo_label = tkinter.Label(self, text='Repository')
self.lbl_repo = tkinter.Label(
self, textvariable=self.repo_path, relief=SUNKEN, anchor=W
)
self.btn_refresh = tkinter.Button(
self, text='Refresh', command=self.refresh_repo
)
self.btn_change = tkinter.Button(
self, text='Change', command=self.change_repo
)
self.status_label = tkinter.Label(self, text='Status')
self.lbl_status = tkinter.Label(
self, textvariable=self.repo_status, relief=SUNKEN, anchor=W,
justify=LEFT
)
self.branch_label = tkinter.Label(self, text='Branch')
self.lbl_branch = tkinter.Label(
self, textvariable=self.repo_branch, relief=SUNKEN, anchor=W
)
self.chk_commit = tkinter.Checkbutton(
self, text='Commit', variable=self.option_commit,
command=self.on_commit_click
)
self.ent_branch_name = tkinter.Entry(
self, textvariable=self.new_branch_name
Context
StackExchange Code Review Q#144238, answer score: 2
Revisions (0)
No revisions yet.