>> I'm using Windows XP, using IDLE (which was mentioned already)
> in the context of editing/displaying code, not executing it. Does the
> problem occur before or after you edit a file with IDLE?
Actually, neither. I'm not editing the code. I open it in IDLE in 2.5
and attempt to run it through the Run menu "Run Module" menu item or
by pressing F5. It immediately fails with a tabnanny error. If I run
it from 2.4's IDLE, it works.
>> and I
>> downloaded the 2.5.1 exe/msi file from python.org to install it.
> What you downloaded doesn't answer the question about how you
> installed it. Do you still have your 2.4 installation?
Yes, I use both 2.4 and 2.5 as I migrate from one to the other. I've
attached a file that causes it consistently. On two systems with both
2.4 and 2.5 installed, it fails on line 206 when run from the IDLE
included with 2.5.
>> I have yet to find a simple one which exhibits the issue to post. It
>> seems to happen to my complex files, not the simple ones.
> So chop up a complex file ...
> Have you inspected the failing files using a text editor that can
> display tabs and spaces (e.g. PythonWin, TextPad)?
I just used Notepad++ to inspect the file and it does indeed have tabs
at line 206 rather than spaces. I take it that Python 2.5 is more
sensitive to that than is 2.4? I program almost exclusively in IDLE as
I'd read that this can happen in some text editors, but it seemed
implied that it didn't if you used IDLE. At least, that's what I got
from various Python books and the website:
http://www.python.org/idle/doc/idlemain.html
Anyway, thanks for the help.
Mike
# scrubber.pyw
#
# Author: Mike Driscoll
#
# Updated: 05/16/2007
#
# Deletes folders and files, ignores errors. The deletion functions
# run in a separate thread.
import wx
import os
import glob
import sys
import shutil
import time
import win32api
from threading import Thread
userid = win32api.GetUserName()
class ProfileScrubber(wx.App):
def __init__(self, redirect=True, filename=None):
wx.App.__init__(self, redirect, filename)
def OnInit(self):
self.frame = wx.Frame(None, -1, title='Profile Scrubber Beta 0.3',
size=(400,500))
panel = wx.Panel(self.frame, -1)
# user list up-to-date as of 10/20/2006
user_list = self.getProfileList()
tempF = r'C:\Documents and Settings\%s\Local Settings\Temp' % userid
tempIntF = r'C:\Documents and Settings\%s\Local Settings\Temporary
Internet Files' % userid
# Create the controls
descriptionLbl = wx.StaticText(panel, -1, ' Choose an option below:')
font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)
descriptionLbl.SetFont(font)
genericPathLbl = wx.StaticText(panel, -1, 'Enter Path:')
self.path = wx.TextCtrl(panel, -1, '', size=(500,-1))
optionLbl = wx.StaticText(panel, -1, 'Other Folders to be Deleted:')
optionLbl.SetFont(font)
self.tempCkbx = wx.CheckBox(panel, -1, 'Temp', size=wx.DefaultSize)
self.tempCkbx.SetValue(True)
self.tempFilesCkbx = wx.CheckBox(panel, -1, 'Temporary Internet Files',
size=wx.DefaultSize)
self.tempFilesCkbx.SetValue(True)
self.tempTxt = wx.TextCtrl(panel, -1, tempF, size=(500,-1))
self.tempTxt.Disable()
self.tempFilesTxt = wx.TextCtrl(panel, -1, tempIntF, size=(500,-1))
self.tempFilesTxt.Disable()
useridLbl = wx.StaticText(panel, -1, 'Choose the user \n(if
different):')
self.user = wx.ComboBox(panel, -1, userid, None, (150, -1), user_list,
wx.CB_DROPDOWN)
self.user.Bind(wx.EVT_COMBOBOX, self.comboChoice)
scrubBtn = wx.Button(panel, -1, 'Scrub')
self.Bind(wx.EVT_BUTTON, self.scrub, scrubBtn)
closeBtn = wx.Button(panel, -1, 'Close')
self.Bind(wx.EVT_BUTTON, self.close, closeBtn)
# create a checklistbox widget to list all the user profiles on the
machine
profLbl = wx.StaticText(panel, -1, 'Please choose what profiles to
remove:')
profLbl.SetFont(font)
self.profile_list = self.getProfileList()
self.profile_cblb = wx.CheckListBox(panel, -1, size=(100, -1),
choices=self.profile_list)
# delete button
deleteBtn = wx.Button(panel, -1, 'Delete Profiles')
self.Bind(wx.EVT_BUTTON, self.deleteProfile, deleteBtn)
# Main sizer to hold all the lesser sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(descriptionLbl)
mainSizer.Add((10,10))
# pathSizer holds the top set of widgets
pathSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
pathSizer.AddGrowableCol(1)
pathSizer.Add(genericPathLbl, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
pathSizer.Add(self.path, 0, wx.EXPAND)
pathSizer.Add(useridLbl, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
pathSizer.Add(self.user, 1)
pathSizer.Add((10,10))
pathSizer.Add((10,10))
pathSizer.Add((10,10))
pathSizer.Add((10,10))
pathSizer.Add(optionLbl,0)
pathSizer.Add((10,10))
pathSizer.Add(self.tempCkbx,0)
pathSizer.Add(self.tempTxt,1)
pathSizer.Add(self.tempFilesCkbx,0)
pathSizer.Add(self.tempFilesTxt,1)
# btnSizer (holds the scrub & close buttons)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add(scrubBtn)
btnSizer.Add((20,20), 1)
btnSizer.Add(closeBtn)
pathSizer.Add((10,10))
pathSizer.Add(btnSizer, 1, wx.ALIGN_CENTER)
# Profile Sizer (holds the check box / combobox and its delete button)
profSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
profSizer.Add(profLbl, 0)
profSizer.Add((10,10))
profSizer.Add(self.profile_cblb, 0)
profSizer.Add((10,10))
profSizer.Add(deleteBtn, 0)
# Add the pathSizer to mainSizer
mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.ALL, 10)
mainSizer.Add(profSizer, 0, wx.EXPAND|wx.ALL, 10)
panel.SetSizer(mainSizer)
mainSizer.Fit(self.frame)
mainSizer.SetSizeHints(self.frame)
# initialize the thread
self.iniThread()
# ---- Make the app visible / OnInit requires a boolean "return"
self.frame.Show(True)
return True
def comboChoice(self, event):
''' On choice, change the two "Temp" directory paths to match the user
choice. '''
self.tempTxt.SetValue('')
self.tempFilesTxt.SetValue('')
new_user = event.GetString()
self.tempTxt.AppendText(r'C:\Documents and Settings\%s\Local
Settings\Temp' % new_user)
self.tempFilesTxt.AppendText(r'C:\Documents and Settings\%s\Local
Settings\Temporary Internet Files' % new_user)
def scrub(self, event):
''' Delete the folders that the user has chosen. '''
folders = []
x = 0 # Used to control what gets popped
tempck = self.tempCkbx.GetValue()
tempFiles_ck = self.tempFilesCkbx.GetValue()
user_path = self.path.GetValue()
paths = [self.path, self.tempTxt, self.tempFilesTxt]
if tempck == False:
paths.pop(1)
x = 1
if tempFiles_ck == False:
if x: # if true, then there's only 2 values, so pop the 2nd
paths.pop(1)
else: # if false, there's 3 values, so pop the 3rd
paths.pop(2)
# Create a list of paths to be deleted
for path in paths:
if path.GetValue() != '':
folders.append(path.GetValue())
# If the user doesn't enter a path and unchecks both boxes, let the
user know!
if tempck == False and tempFiles_ck == False and user_path == '':
dlg = wx.MessageDialog(None, 'You need to enter a path or check a
checkbox to delete.',
'Information', wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
# Get response code
resCode = self.warningMessage(folders)
# Delete the folder(s) if user chose "Yes"
if (resCode == wx.ID_YES):
t = time.ctime()
print '**************************************************'
print '\nNew Scrub Job accepted %s\n' % t
print '**************************************************'
FDeleteThread(self, folders)
def warningMessage(self, folders):
''' Create a custom warning message for the user based on his choices.
'''
if len(folders) == 3:
response = wx.MessageDialog(None, 'This will attempt to delete
these folder\'s subfolders:\n\n%s\n%s\n%s\n\nIs this OK?' %
(folders[0],folders[1],folders[2]),
'WARNING', wx.YES_NO |
wx.ICON_QUESTION)
resCode = response.ShowModal()
response.Destroy()
elif len(folders) == 2:
response = wx.MessageDialog(None, 'This will attempt to delete
these folder\'s subfolders:\n\n%s\n%s\n\nIs this OK?' % (folders[0],folders[1]),
'WARNING', wx.YES_NO |
wx.ICON_QUESTION)
resCode = response.ShowModal()
response.Destroy()
elif len(folders) == 1:
response = wx.MessageDialog(None,'This will attempt to delete this
folder\'s subfolders:\n\n%s\n\nIs this OK?' % (folders[0]),
'WARNING', wx.YES_NO |
wx.ICON_QUESTION)
resCode = response.ShowModal()
response.Destroy()
else:
pass
return resCode
def getProfileList(self):
''' Search "Documents and Settings" folder and create a list of user
profiles. '''
userPaths = glob.glob(r'c:\documents and settings\\*')
user_list = []
for i in userPaths:
if len(i[26:]) > 6:
pass
elif i[26:].upper() == userid:
pass
else:
user_list.append(i[26:])
return user_list
def deleteProfile(self, event):
''' Delete the profile(s). '''
prof_list = []
count = 0
resCode = ''
prof_dir = r'C:\Documents and Settings'
# Check if any profiles are checked and create a list of them.
for i in self.profile_list:
if self.profile_cblb.IsChecked(count):
print '%s is checked' % i
prof_list.append(i)
else:
print '%s is NOT checked' % i
count += 1
# Warn user about deleting profiles
if len(prof_list) > 0:
response = wx.MessageDialog(None, 'Do you really want to delete
these profile(s)?',
'WARNING', wx.YES_NO |
wx.ICON_QUESTION)
resCode = response.ShowModal()
response.Destroy()
# If "Yes" is chosen, delete the checked profiles
if resCode == wx.ID_YES:
for x in prof_list:
print prof_dir + '\\%s' % x
#shutil.rmtree(prof_dir + '\\%s' % x, ignore_errors=True)
#os.system(r'RD /S /Q "%s"' % (prof_dir + '\\%s' % x))
subprocess.Popen(r'RD /S /Q "%s"' % (prof_dir + '\\%s' % x),
shell=True)
print 'Finished deleting selected profiles.'
# Clear the combo-listbox
self.profile_cblb.Clear()
print 'cleared'
self.profile_cblb.AppendItems(self.getProfileList())
def iniThread(self):
''' Initialize thread object. '''
##### beginning of threading code setup #####
# Set up event handler for any worker thread results
EVT_RESULT(self,self.onResult)
# And indicate we don't have a worker thread yet
self.worker = None
###### end of threading code #######
def onResult(self, event):
''' Reset the worker thread to None. '''
print 'Thread has finished!'
self.worker = None
def close(self, event):
''' Close the window '''
self.frame.Close(True)
#####################################################################################
EVT_RESULT_ID = wx.NewId()
def EVT_RESULT(win, func):
"""Define Result Event."""
win.Connect(-1, -1, EVT_RESULT_ID, func)
class ResultEvent(wx.PyEvent):
"""Simple event to carry arbitrary result data."""
def __init__(self, data):
"""Init Result Event."""
wx.PyEvent.__init__(self)
self.SetEventType(EVT_RESULT_ID)
self.data = data
class FDeleteThread(Thread):
"""Printer Child Thread Class."""
def __init__(self, notify_window, fList):
"""Init Worker Thread Class."""
Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = 0
self.folders = fList
self.start() # start the thread
def run(self):
"""Run Worker Thread."""
for folder in self.folders:
dirs = glob.glob(folder + '\\*')
files = glob.glob(folder + '\\*.*')
for d in dirs:
if os.path.isdir(d):
self.delete2(d)
# END IF
# END INNER FOR LOOP
for f in files:
try:
os.remove(f)
except:
print 'ERROR - Could not remove: %s' % f
print 'Scrubbing finished!'
wx.PostEvent(self._notify_window, ResultEvent(10))
def delete2(self, item):
if os.path.isdir(item):
try:
print '\nDeleting %s' % item
shutil.rmtree(item)
except:
#os.system(r'RD /S /Q "%s"' % item)
subprocess.Popen(r'RD /S /Q "%s"' % item, shell=True)
else:
try:
os.remove(item)
except:
#os.system('DEL /F /S /Q "%s"' % item)
subprocess.Popen(r'DEL /F /S /Q "%s"' % item, shell=True)
if __name__ == '__main__':
app = ProfileScrubber()
app.MainLoop()
--
http://mail.python.org/mailman/listinfo/python-list