Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have this script for creating SQLite backups, and I was wondering whether you'd have any suggestions on how to improve this. I was thinking that maybe it should create the backup dir if it doesn't exist, but not sure if it's necessarily better.

Besides functionality/performance tips, any styling/formatting tips are also much appreciated.

#!/usr/bin/env python
"""
This script creates a timestamped database backup,
and cleans backups older than a set number of dates

"""    

from __future__ import print_function
from __future__ import unicode_literals

import argparse
import sqlite3
import shutil
import time
import os

DESCRIPTION = """
              Create a timestamped SQLite database backup, and
              clean backups older than a defined number of days
              """

# How old a file needs to be in order
# to be considered for being removed
NO_OF_DAYS = 7

def sqlite3_backup(dbfile, backupdir):
    """Create timestamped database copy"""

    if not os.path.isdir(backupdir):
        raise Exception("Backup directory does not exist: {}".format(backupdir))

    backup_file = os.path.join(backupdir, os.path.basename(dbfile) +
                               time.strftime("-%Y%m%d-%H%M%S"))

    connection = sqlite3.connect(dbfile)
    cursor = connection.cursor()

    # Lock database before making a backup
    cursor.execute('begin immediate')
    # Make new backup file
    shutil.copyfile(dbfile, backup_file)
    print ("\nCreating {}...".format(backup_file))
    # Unlock database
    connection.rollback()

def clean_data(backup_dir):
    """Delete files older than NO_OF_DAYS days"""

    print ("\n------------------------------")
    print ("Cleaning up old backups")

    for filename in os.listdir(backup_dir):
        backup_file = os.path.join(backup_dir, filename)
        if os.stat(backup_file).st_ctime < (time.time() - NO_OF_DAYS * 86400):
            if os.path.isfile(backup_file):
                os.remove(backup_file)
                print ("Deleting {}...".format(ibackup_file))

def get_arguments():
    """Parse the commandline arguments from the user"""

    parser = argparse.ArgumentParser(description=DESCRIPTION)
    parser.add_argument('db_file',
                        help='the database file that needs backed up')
    parser.add_argument('backup_dir',
                         help='the directory where the backup'
                              'file should be saved')
    return parser.parse_args()

if __name__ == "__main__":
    args = get_arguments()
    sqlite3_backup(args.db_file, args.backup_dir)
    clean_data(args.backup_dir)

    print ("\nBackup update has been successful.")
share|improve this question
    
Note that SQLite has an Online Backup API, though unfortunately it does not appear to be available through Python. –  200_success Jan 26 at 20:39

2 Answers 2

up vote 3 down vote accepted

This looks like a pretty nice script to me.

I was thinking that maybe it should create the backup dir if it doesn't exist, but not sure if it's necessarily better.

I don't think there's a universal answer to that, it's your call how you want the script to behave. It depends on your use whether you need the script to create a backup directory if it doesn't exist, or if you want to avoid it creating directories at unintended locations. A compromise might be to add a -p flag like mkdir has to "create parents".

Not that it really matters, but I think it should be slightly more efficient, and more natural to flip these conditions:

    if os.stat(backup_file).st_ctime < (time.time() - NO_OF_DAYS * 86400):
        if os.path.isfile(backup_file):

That is:

    if os.path.isfile(backup_file):
        if os.stat(backup_file).st_ctime < (time.time() - NO_OF_DAYS * 86400):

You seem to be following PEP8 for the most part, with few exceptions:

  • Don't put a space before parentheses, as in print (something)
  • Put two empty lines in front of function definitions
share|improve this answer

There's no need to repeat yourself by defining DESCRIPTION (and in fact your strings have gotten out of sync). Just reuse the program's docstring:

def get_arguments():
    """Parse the commandline arguments from the user"""    
    parser = argparse.ArgumentParser(description=__doc__)
    …
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.