DEV Community

Cover image for Training a Snake to Clean my Desktop
Milnor
Milnor

Posted on

Training a Snake to Clean my Desktop

The Task

The final project in the Coding Nomads Python 101 course is to write (1) a Python script that automatically cleans your Desktop by moving all screenshots to a new folder; and (2) writing a blog post about said script.

I began the project by looking at my actual Desktop and thinking about how to tailor the stated task to meet my actual needs. A minimally acceptable solution is to create a new folder and transfer all .png images into it, but that would hardly make a dent in the 99 items contained in C:\Users\MyName\Desktop. Therefore, my revised plan is to automatically move:

  • .pngs, .svgs, and .gifs into a new subdirectory, PICS;
  • .txts, .mds, and .rtfs into NOTES;
  • .pdfs into PDFS; and
  • .c source files into CODE.
Yes, I have outed myself. I am a C developer. You won't find a lick of Python on my cluttered Desktop, yet.

Setting the Path to my Desktop

If I were coding this tool at work, the path to the Desktop would likely be set via a command line argument. However, we haven't "officially" learned to parse command line arguments with sys.argv() or argparse yet. Another option would be to prompt for user input, but during a lab exercise, I had a bad experience where I meant to type C:\Users\MyName\Desktop\TestFolder, but I missed the \ key and hit Enter early, mistakenly running faulty work-in-progress code against my actual Desktop! (Fortunately, that script crashed after moving a single file to where I didn't want it). In the interest of safety, I will hardcode the path thus:

desktop = pathlib.Path(r"C:\Users\MyName\Desktop\TestFolder")
Enter fullscreen mode Exit fullscreen mode

Only after I've tested the script against TestDir will I shorten the path to run things against my Desktop for real.

Giving credit where credit is due, Stack Overflow straightened me out when my initial code was wrong. The Windows path separator \ easily collides with Unicode escape sequences, so I added r to create a raw string, slightly easier than escaping each path separator.

Creating the New Directories

Since I want to create a series of new directories, not just one, I iterated through a list of names, joining them to the desktop path.

for sub_dir in ["CODE", "NOTES", "PDFS", "PICS"]:
    new_dir = desktop.joinpath(sub_dir)
    new_dir.mkdir(exist_ok=True)
Enter fullscreen mode Exit fullscreen mode

The exist_ok argument should make testing less tedious, since the script won't error out if run in succession without deleting the new folders in between.

Identifying and Relocating Files

A hefty for loop did all the heavy lifting.

# Filter for screenshots only
for each in desktop.iterdir():
    if not each.is_file():
        # Skip directories
        continue

    extension = each.suffix.lower()

    # Create a new path for each file
    if extension in [".c", ".h", ".py"]:
        # put it in CODE
        new_path = desktop / "CODE" / each.name

    elif extension in [".md", ".rtf", ".txt"]:
        # put it in NOTES
        new_path = desktop / "NOTES" / each.name

    elif extension == ".pdf":
        # put it in PDFS
        new_path = desktop / "PDFS" / each.name

    elif extension in [".bmp", ".gif", ".jpg", ".jpeg", ".svg", ".png"]:
        # put it in PICS
        new_path = desktop / "PICS" / each.name

    else:
        continue
Enter fullscreen mode Exit fullscreen mode

First, I iterated through every file on the Desktop using iterdir(). Second, to recognize file types in a case-insensitive fashion, I converted the suffix of each file to lowercase and tested whether it was found in a list of file extensions belonging to the same category. Third, I set a new_path variable with the future location of the file. As a convenience, pathlib.Path supports building paths using the / operator; I find that more readable than the joinpath() method when you have multiple pieces to string together.

files_moved = 0

....

# Move the screenshot there
print(f"[!] Moving {each} to {new_path}...")
each.rename(new_path)
files_moved += 1
Enter fullscreen mode Exit fullscreen mode

Finally, each file from the for loop was moved to new_path using the rename() method. For my own edification, I added a files_moved variable to quantify the work completed by the automation script.

Running it...

When I changed the path from the test directory to my actual Desktop, the script proudly reported [+] Successfully moved 41 files!. This was nice and all, but a quick visual inspection told me that the PDFs stayed put. Notice that unlike the other categories of files, there is only one valid file extension for a PDF. The initial version of my code had a silly logic bug that was syntactically valid: elif extension == [".pdf"]:. After quickly fixing that and re-running the script, 16 additional files were relocated.

Now, with my Desktop in a semblance of order, I can tackle individual subdirectories at my leisure and delete any files that do not spark joy.

Custom KonMari meme that suggests vacation photos spark joy but credit card statements do not

Complete Code Listing

# Write a script that moves all files with the .png extension
# from one folder to another
""" Clean up my Desktop Automagically """

import pathlib

# Find the path to my Desktop
desktop = pathlib.Path(r"C:\Users\MyName\Desktop")

# Create a new folder
for sub_dir in ["CODE", "NOTES", "PDFS", "PICS"]:
    new_dir = desktop.joinpath(sub_dir)
    new_dir.mkdir(exist_ok=True)

files_moved = 0

# Filter for screenshots only
for each in desktop.iterdir():
    if not each.is_file():
        # Skip directories
        continue

    extension = each.suffix.lower()

    # Create a new path for each file
    if extension in [".c", ".h", ".py"]:
        # put it in CODE
        new_path = desktop / "CODE" / each.name

    elif extension in [".md", ".rtf", ".txt"]:
        # put it in NOTES
        new_path = desktop / "NOTES" / each.name

    elif extension == ".pdf":
        # put it in PDFS
        new_path = desktop / "PDFS" / each.name

    elif extension in [".bmp", ".gif", ".jpg", ".jpeg", ".svg", ".png"]:
        # put it in PICS
        new_path = desktop / "PICS" / each.name

    else:
        continue

    # Move the screenshot there
    print(f"[!] Moving {each} to {new_path}...")
    each.rename(new_path)
    files_moved += 1

if files_moved > 0:
    print(f"[+] Successfully moved {files_moved} files!")

Enter fullscreen mode Exit fullscreen mode

Top comments (0)