0

Suppose I have a set of file rename operations:

renames={(current_1,new_1),(current_2,new_2),...}

It is guaranteed that the files current_1,current_2,... exist and that the new files new_1,new_2,... are unique. All files are instances of pathlib.Path.

They may be, however, files that are currently named as another file has to be renamed: i.e. it may exist an instance of current_i==new_j.

What would be an elegant way to implement the rename operations? Note that I can't just iterate over renames and rename each file, because I have to be prepared for a situation where the new name conflicts with the name of a file yet to be renamed.

I'm specifically looking for an implementation in Python3, and I would like renames to be kept a set in the form above.

A simple way is to temporarily prefix the files:

temporal_prefix="a big string guaranteed not to appear in file names"
for current,new in renames:
    current.rename(current.with_name(temporal_prefix+current.name))
for current,new in renames:
    current.with_name(temporal_prefix+current.name).rename(new)

But this is not very elegant and it requires up to double the needed file operations. And finding a good prefix may be a problem in and of itself. Is it possible to do this in one loop, using the minimum number of file operations?

Saúl Pilatowsky-Cameo
  • 1,224
  • 1
  • 15
  • 20

1 Answers1

1

There isn't much point trying to be too clever because renaming isn't an expensive operstion and the error you get when a file exists is pretty clear and can be trapped and dealt with. You can even test for the existence of each file first and avoid having to trap errors if you want but if you think most files won't have a problem it's probably a waste of time

Just use a data structure like a queue to hold your renames, start processing them from head to tail and upon finding a failure due to existing, put the rename back on the end of the queue so your loop will come around to it again later. Most renames will probably succeed first time, those that don't will probably succeed second time

I havent don't posted any example code because I've never touched python in my life (sorry). In pseudocode I would:

While(renameQueue.hasItems)
  to_rename = renameQueue.dequeue()
  Try
    File.Rename(to_rename.oldName, to-rename.newName)
  OnError FILE_EXISTS
    new_name = system.getRandomTempFilename()
    File.Rename(to_rename.oldName, new_name)
    to_rename.oldName = new_name
    renameQueue.enqueue(to_rename)
  End Try
End While
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • 1
    Wait... I've run into a problem with this. For something like [(A,B),(B,A)] where both A and B exist... the loop will never exit. In general this happens if there is a closed "chain" of renames. – Saúl Pilatowsky-Cameo Aug 05 '17 at 06:32
  • It's a good point; it looks like quite a narrow edge case in that it's restricted to pairs that seek to swap the names over or worse, cycle names around (ab,bc,ca). Perhaps extend the re-enqueue logic so that it renames the file right now to a temp random file name and put this new tempname-> desired name pair on the queue – Caius Jard Aug 05 '17 at 22:36