Create a Command-Line Tool with Python

By Raman Kumar

Updated on Nov 30, 2024

In this tutorial, we'll learn how to create a command-line tool with Python using the powerful argparse module. This step-by-step tutorial walks you through building a file organizer that sorts files into subfolders by their extensions. 

With in-depth explanations, best practices, and reusable code, this guide is perfect for developers looking to enhance their Python skills and build robust CLI tools. Command-line tools are a cornerstone of modern software, offering powerful ways to automate tasks and streamline workflows. Python's argparse module is a robust library for building such tools. 

What is argparse?

The argparse module simplifies the process of creating user-friendly command-line interfaces. It parses command-line arguments and provides meaningful help messages and error handling. With argparse, you can define arguments, specify their data types, set default values, and more.

Key Concepts of argparse

  • Arguments: Parameters passed to the tool, such as options (--verbose) or positional arguments (e.g., filenames).
  • Parser: An ArgumentParser object handles parsing and validation of arguments.
  • Actions: Define what happens when an argument is encountered (e.g., store a value or trigger a function).
  • Example Scenario: A File Organizer Tool

We’ll build a command-line tool called organizer. It organizes files in a directory by their extensions into subfolders.

Create a Command-Line Tool with Python

Step-by-Step Implementation

Step 1: Setting Up the Environment

Ensure you have Python 3.8 or later installed. Create a new directory for your project and set up a virtual environment:

mkdir organizer-tool
cd organizer-tool
python3 -m venv venv
source venv/bin/activate

Install any required libraries (none for this tutorial) and create the organizer.py file.

Step 2: Writing the Code

Create the organizer.py file

nano organizer.py

Add following production-grade code:

import argparse
import os
import shutil
from pathlib import Path

def organize_files(directory, dry_run=False):
    """
    Organizes files in the specified directory into subfolders based on their extensions.

    Args:
        directory (str): Path to the directory to organize.
        dry_run (bool): If True, show what would happen without making changes.
    """
    directory_path = Path(directory)
    if not directory_path.is_dir():
        raise ValueError(f"'{directory}' is not a valid directory.")

    files_moved = 0
    for file in directory_path.iterdir():
        if file.is_file():
            extension = file.suffix[1:] or "no_extension"
            target_dir = directory_path / extension

            if dry_run:
                print(f"[DRY RUN] Would move {file.name} to {target_dir}/")
            else:
                target_dir.mkdir(exist_ok=True)
                shutil.move(str(file), str(target_dir))
                files_moved += 1

    if dry_run:
        print(f"[DRY RUN] Total files that would be moved: {files_moved}")
    else:
        print(f"Organized {files_moved} files into subfolders.")

def main():
    """
    Main entry point for the command-line tool.
    """
    parser = argparse.ArgumentParser(
        description="Organize files in a directory into subfolders based on file extensions."
    )
    
    parser.add_argument(
        "directory",
        type=str,
        help="The directory to organize."
    )
    
    parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Show what would happen without making changes."
    )
    
    parser.add_argument(
        "--version",
        action="version",
        version="organizer 1.0",
        help="Show the version number and exit."
    )

    args = parser.parse_args()

    try:
        organize_files(args.directory, args.dry_run)
    except Exception as e:
        print(f"Error: {e}")
        exit(1)

if __name__ == "__main__":
    main()

Step 3: Understanding the Code

1. argparse.ArgumentParser

  • Defines the parser with a description of the tool.
  • Positional arguments like directory specify required inputs.
  • Optional arguments like --dry-run and --version add functionality.

2. organize_files Function

  • Validates the directory.
  • Groups files into subfolders by extension.
  • Supports a dry_run mode for safe testing.

3. main Function

  • Acts as the tool's entry point.
  • Parses arguments and handles exceptions gracefully.

4. File Operations

  • Uses Path from pathlib for cleaner path manipulations.
  • Employs shutil.move for robust file moving.

Step 4: Testing the Tool

Save the script as organizer.py and make it executable:

chmod +x organizer.py

1. Test with a directory:

python organizer.py /path/to/directory

2. Dry run mode:

python organizer.py /path/to/directory --dry-run

3. Check version:

python organizer.py --version

Step 5: Packaging for Distribution

To make the tool reusable, package it for distribution using setuptools.

Create setup.py:

nano setup.py

Add following code:

from setuptools import setup, find_packages

setup(
    name="organizer",
    version="1.0",
    packages=find_packages(),
    entry_points={
        "console_scripts": [
            "organizer=organizer:main",
        ],
    },
    install_requires=[],
    python_requires=">=3.8",
    description="A tool to organize files into subfolders based on extensions.",
    author="Your Name",
    author_email="your.email@example.com",
    url="https://example.com/organizer",
)

Install Locally:

pip install .

You can now invoke the tool globally:

organizer /path/to/directory

Conclusion

In this tutorial, we'll learnt how to create a command-line tool with Python using the powerful argparse module. By following this guide, you’ve created a professional-grade command-line tool using Python's argparse. This tool features robust error handling, extensibility, and clean packaging. You can build on this foundation to create more complex tools by adding features like logging, advanced argument parsing, or support for different file operations.

Checkout our instant dedicated servers and Instant KVM VPS plans.