Search code examples
pythonpython-3.xfile-renameos.walk

Python unexpectedly moving files with os.rename


I have a script that:

  1. Loops through all the files in a directory + its subdirectories
  2. Creates folder for each unique year in the list of files
  3. Moves files to their respective folder years
  4. Renames them based on timestamp + unique number.

When I run parts 1-3 only, it moves the files to the folders correctly.

When I run parts 1-4 (including the os.rename part), it renames the files AFTER moving them back to the parent directory.

Start file structure:

parent_folder
      --> file.txt    modified 01-21-2012
      --> file2.txt   modified 09-30-2013
      --> file3.txt   modified 06-21-2017

Expected result:

parent_folder
--> '2012'
      --> 2012-01-21-1.txt
--> '2013'
      --> 2013-09-30-2.txt
--> '2017'
      --> 2017-06-21-3.txt

Actual result:

parent_folder
--> '2012'
--> '2013'
--> '2017'
--> '2012-01-21-1.txt'
--> '2013-09-30-2.txt'
--> '2017-06-21-4.txt'

As you can see, it renamed the files but moved them out of their folders. Why is it doing this?

My code (I inserted print statements for logging):

import os, datetime, sys, shutil

#PART 1 : Change to the inputted directory
#===============================

# This is the directory I will work on.
p = 'ENTER_FOLDER_PATH_HERE'
print('This is the directory that will be organized:')
print(os.getcwd())
if os.path.isdir(p): # check if directory exists
    print("Step 1: Changing directory")
    os.chdir(p)

#PART 2 : Make a folder for each unique year
#===========================================
    fileNames = next(os.walk(os.getcwd()))[2] # list files, excluding subdirectories
    f = {}
    filename = []
    dates = []

    # Loop through each file and grab the unique year.
    # Store the file (key) and its modified year (value) into dictionary 'f'.
    for name in fileNames:
        f[name] = datetime.datetime.fromtimestamp(os.path.getmtime(name)).strftime("%Y")
        dates = list(set(f.values()))

    # Create the list of unique folders from the dictionary.
    print("Step 2: Creating the following folders:\n", dates)
    print('\n')
    [os.mkdir(folder) for folder in dates]


#PART 3: Move all files to their respective folders based on modified year.
#==========================================================================
    if sys.platform == 'Windows':
        print("Step 3: moving files...")
        [shutil.move(key, os.getcwd() + '\\' + value) for key, value in f.items()]
    elif sys.platform == 'darwin':
        print("Step 3: moving files...")
        [shutil.move(key, os.getcwd() + '//' + value) for key, value in f.items()]
    else:
        print("Sorry, this script is not supported in your OS.")
else:
    print("Oops, seems like that directory doesn't exist. Please try again.")


#PART 4: Rename the files
#==========================================================================
# Get each file in directory and renames it to its modified date, Y-M-D format
count=1
for root, dir, files in os.walk(p):
    for file in files:
        if not file.startswith('.'): # ignore hidden files
            filePath = os.path.join(root,file)
            ext = os.path.splitext(filePath)[1]
            print("File number: ", count, file, ext)
            print('\n')
            os.rename(filePath, datetime.datetime.fromtimestamp(os.path.getmtime(filePath)).strftime("%Y-%m-%d") + '-' + str(count) + ext)
        count += 1
        print(filePath)

Logs:

This is the directory that will be organized:
TEST_PATH
Step 1: Changing directory
Step 2: Creating the following folders:
 ['2013', '2012', '2017']


Step 3: moving files...
File number:  1 2012-01-21-1.jpg TEST_PATH/2012/2012-01-21-1.jpg
TEST_PATH//2012/2012-01-21-1.jpg

File number:  2 2013-09-30-2.jpg TEST_PATH/2013/2013-09-30-2.jpg
TEST_PATH/2013/2013-09-30-2.jpg
TEST_PATH/2013/2013-09-30-2.jpg

File number:  4 June 21 2017.txt TEST_PATH/2017/June 21 2017.txt
TEST_PATH/2017/June 21 2017.txt

Solution

  • It moves the file, because of the working directory you are currently in. I gues it works just like mv command. The resulting file, after raname, will be put in a path specified by the second argument of the os.rename function, relative to cwd. If you want it to work correctly you need to specify the relative path with the new filename.

    Btw. you can do steps 3&4 at once this way.