Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
244: The shutil Module for File Operations
I've seen this mistake happen a dozen times when people start building automation scripts. You have a folder full of logs or user uploads, and you want to back it up to another location. Your first instinct is to reach for shutil.copy() because the name seems obvious. It looks like this:
import shutil
import os
source_dir = 'logs_2023'
backup_dir = 'backup_logs_2023'
# I just want to copy the folder over
shutil.copy(source_dir, backup_dir)
When you run this, Python is going to throw an IsADirectoryError (or a PermissionError on some systems). It's frustrating because you're telling Python to copy a directory, and it's telling you that it can't. The problem is that shutil.copy() is designed strictly for files. It doesn't know how to recurse into a folder, grab all the files inside, create the corresponding directory structure at the destination, and move them over.
Switching to recursive directory copying
To fix this, you need shutil.copytree(). Unlike the basic copy function, copytree is designed specifically for directories. It walks through the entire source tree and replicates it exactly at the destination.
import shutil
source_dir = 'logs_2023'
backup_dir = 'backup_logs_2023'
# This handles the directory and everything inside it
shutil.copytree(source_dir, backup_dir)
One thing to keep in mind: copytree expects the destination directory to not exist yet. If backup_logs_2023 already exists, Python will raise a FileExistsError. If you're on Python 3.8+, you can get around this by adding the argument dirs_exist_ok=True.
Preserving metadata with copy2
Now, if you are copying individual files, you'll notice shutil.copy() copies the file and the permissions, but it doesn't preserve the original creation and modification timestamps. In a production environment—especially when dealing with logs or legal documents—those timestamps are critical.
I always recommend using shutil.copy2() instead. It does everything copy() does, but it also attempts to preserve all the file metadata. It's a small change in the function name, but it saves you from a massive headache during a forensic audit later on.
Moving files across different drives
You might be tempted to use os.rename() to move files. That works fine as long as you're moving a file within the same partition. But the moment you try to move a file from a local SSD to a network drive or a USB stick, os.rename() will fail with an OSError because it can't perform a rename across different file systems.
shutil.move() is the professional's choice here. It first tries to rename the file, but if that fails because the destination is on a different disk, it transparently copies the file over and then deletes the original. You don't have to write any logic to handle the "cross-device" edge case; shutil handles it for you.
Wiping directories and creating archives
Cleaning up is just as important as copying. If you need to delete a directory and everything inside it, os.rmdir() won't work unless the folder is already empty. To nuking a directory regardless of its contents, use shutil.rmtree(). Be careful with this one—there is no "Recycle Bin" here. Once it's gone, it's gone.
Finally, if you need to bundle a directory into a single file for transport, shutil.make_archive() is your best friend. It wraps the complexity of the zipfile or tarfile modules into a single line of code.
import shutil
# Creates 'project_backup.zip' from the 'my_project' folder
shutil.make_archive('project_backup', 'zip', 'my_project')
📋 Practical Task
Build a Project Snapshot and Cleanup Utility
Create a Python script that performs the following sequence of operations to simulate a build-and-archive workflow:
- Create a directory named
build_outputand place two dummy text files inside it. - Use
shutil.copytree()to create a backup ofbuild_outputnamedbuild_backup. - Use
shutil.make_archive()to compress thebuild_backupfolder into a zip file namedfinal_release. - Use
shutil.rmtree()to delete both thebuild_outputandbuild_backupdirectories, leaving only thefinal_release.zipfile behind.
Ensure your script handles the case where the backup directory might already exist from a previous run.
There are no comments for now.