Reputation: 5534
Ok folks, here's a weird one.
Theres' a GUI (in wxPython) which allows files to be attached. The file paths are saved to class attribute self.pathList
. These paths are displayed on the GUI and edited with two functions (bound to buttons); OnAttach()
and OnView()
. The first, as the name implies, allows the user to select files, while the second allows the user to see a list of those files and choose which ones to delete.
There are two problems:
[SOLVED] The items are added to self.pathList
without any regard for sorting. It doesn't matter if or where sorted()
is applied, the list is never sorted. We test this by selecting 100 text files named "1.txt", "2.txt", and so on. The order seems random. The full code of the two functions is below, but the line in question is this:
self.pathList = list(set(self.pathList + [str(path) for path in sorted(dlg.GetPaths())]))
Again, it doesn't matter where sorted
is applied (or if its there at all), the result is the same. Both lines below return the same self.pathList
:
self.pathList = list(set(self.pathList + [str(path) for path in dlg.GetPaths()]))
self.pathList = sorted(list(set(self.pathList + [str(path) for path in dlg.GetPaths()])))
IndexError: pop index out of range
Hopefully someone can make sense of this. Thanks in advance
def OnAttach(self, event, viewattBtn):
"""Select a File"""
self.dirname = ''
dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN|wx.MULTIPLE|wx.FD_FILE_MUST_EXIST)
if dlg.ShowModal() == wx.ID_OK:
self.pathList = list(set(self.pathList + [str(path) for path in sorted(dlg.GetPaths())]))
for path in self.pathList:
self.fileNameList.append(path.split('\\')[-1])
self.fileNameList = list(set(self.fileNameList)) #Applying sorted() here fixes the first issue
self.att.SetLabel('\n'.join(self.fileNameList))
self.vbox.Layout()
self.panel.FitInside()
if self.pathList != []: viewattBtn.Enable(True)
return viewattBtn
dlg.Destroy()
def OnView(self, event, viewattBtn):
dlg = wx.MultiChoiceDialog(self, "Attachments (Select attachments and push 'OK' to delete)", "", self.fileNameList, wx.OK|wx.CANCEL)
if options.diagMode: print self.fileNameList
if dlg.ShowModal() == wx.ID_OK:
selections = reversed(sorted(dlg.GetSelections()))
selections = [self.fileNameList[index] for index in selections]
for item in selections:
pathIndex = selections.index(item)
self.pathList.pop(pathIndex)
self.fileNameList.remove(item)
self.att.SetLabel('\n'.join(self.fileNameList))
self.vbox.Layout()
self.panel.FitInside()
if self.fileNameList == []: viewattBtn.Enable(False)
return viewattBtn
dlg.Destroy
EDIT: The first problem was fixed by sorted fileNameList
on the marked line
Upvotes: 0
Views: 508
Reputation: 366133
For your first issue, the problem is that you're creating a set
out of the sorted list. Sets have no defined order; in fact, the order is documented to be arbitrary.
The solution is to just not create a set
in the first place.
If you need to eliminate duplicates, you can use a recipe like unique_everseen
from the itertools
docs, or use an OrderedSet
class of some kind. If you don't need to eliminate dups, just use the list as-is:
self.pathList = self.pathList + [str(path) for path in sorted(dlg.GetPaths())]
(Also, if you did want a set, you probably wouldn't want to convert that set to a list and add it to another list; you'd want to just keep it as a set in the first place.)
For your second issue, I'm not sure what your code is trying to do, but it's almost certainly doing things completely wrong.
First, you never want to iterate over a list and then search for the value's index. That does the wrong thing if there are any duplicates, and it's very slow, and it's very complicated. Just keep the index around:
for index, item in enumerate(selections):
Second, I don't think the indexes in selections
have anything to do with the indexes in pathList
and fileNameList
, in which case using the indexes doesn't work right in the first place.
But even if the indexes were the same at the start, every time you pop
something out of the list, all of the remaining elements shift up one, so the indexes are no longer right after the first pop
.
I think it would be better to reorganize your data structure—instead of keeping a bunch of lists, keep one list for whatever the thing is that needs to have a defined order, and keep everything else as dicts, using the values from that first list as keys.
Upvotes: 1
Reputation: 308530
Using a set
will reorder your items, unsorting them. Don't do that, or sort after you've converted the set back to a list.
As you remove items from pathList
the position of items in that list will change, and will no longer correspond to the numbers you're getting from selections
. After you're removed enough items chances are one of the indexes will be beyond the size of the list.
Upvotes: 1