0

i'm trying to make a code which do a scheduled backup and it has to be executed at some point in future(after 10 seconds in example) and i want it to do again after some time (10 seconds). I found threading.Time builtin module and it just stops after one time doing operation. I know it's me doing smth wrong so help me please

import time
import shutil
from datetime import datetime, timedelta
from threading import Timer

# calculating 
x = datetime.today()
bkup = x.replace(second = x.second) + timedelta(seconds = 10)
delta_t=bkup-x
secs=int(delta_t.total_seconds())

# creating an archive
def backup():
    source = 'D:\py'
    target_dir = 'D:\Backup'

    b = '%Y{0}%m{0}%d{0}%H{0}%M{0}%S'.format('.')
    target = target_dir + os.sep + time.strftime(b)

    a = shutil.make_archive(target, 'zip', target_dir, source)

    if os.system(a) == 0:
        print('Backup success!', target)
    else:
        print('Backup fail')


t = Timer(secs, backup)
t.start()



Denya56
  • 60
  • 1
  • 9

2 Answers2

0

The timer only runs once. You could:

  • start a new timer after your back up is done

  • make a while loop in the timer function

  • start your backup with your operating system. In linux this can be done with a cron job, in windows with the task scheduler

Also see this question.

Turun
  • 748
  • 6
  • 7
0

Put your backup code in a separate thread and then have an infinite while loop which waits based on your wait interval. I've attached code down below.

import os
import sys
import shutil
from threading import Thread
import time


class BackupUtil(Thread):
    def __init__(self, interval, src_path, dst_path):
        super().__init__()
        self.interval = interval
        self.src_path = src_path
        self.dst_path = dst_path

    def run(self):
        while True:
            b = '%Y{0}%m{0}%d{0}%H{0}%M{0}%S'.format('.')
            target = self.dst_path + os.sep + time.strftime(b)
            archive = shutil.make_archive(target, 'zip', self.src_path, self.dst_path)

            if os.path.exists(archive):
                print('Backup success!', target)
            else:
                print('Backup failed.')
            time.sleep(self.interval)

if __name__ == '__main__':
    src = sys.argv[1] if os.path.exists(sys.argv[1]) else os.path.join('D', 'py')
    dst = sys.argv[2] if os.path.exists(sys.argv[2]) else os.path.join('D', 'Backup')
    backup = BackupUtil(10, src, dst)
    backup.start()

Alternatively, if you are on linux or running WSL, you can set this to run as a cron job. Add a python shebang to your script #!/usr/bin/env python3 then save your backup script to something like /mnt/c/py/backup_archive I prefer to remove the .py extension so we can easily tell the script is meant to be executable. Lastly, make sure it's actually executable (chmod +x /mnt/c/py/backup_archive or chmod 775 /mnt/c/py/backup_archive).

#!/usr/bin/env python3


import os
import sys
import shutil
from threading import Thread
import time


class BackupUtil(Thread):
    def __init__(self, interval, src_path, dst_path):
        super().__init__()
        self.interval = interval
        self.src_path = src_path
        self.dst_path = dst_path

    def run(self):
        while True:
            b = '%Y{0}%m{0}%d{0}%H{0}%M{0}%S'.format('.')
            target = self.dst_path + os.sep + time.strftime(b)
            archive = shutil.make_archive(target, 'zip', self.src_path, self.dst_path)

            if os.path.exists(archive):
                print('Backup success!', target)
            else:
                print('Backup failed.')
            time.sleep(self.interval)

if __name__ == '__main__':
    src = sys.argv[1] if os.path.exists(sys.argv[1]) else os.path.join('D', 'py')
    dst = sys.argv[2] if os.path.exists(sys.argv[2]) else os.path.join('D', 'Backup')
    backup = BackupUtil(10, src, dst)
    backup.start()

Then add a cron job for the script, setting the interval to 1 minute (doesn't do less than 1 minute intervals by default, don't really think that's necessary either).

crontab -e
1 * * * * /mnt/c/py/backup_archive arg1 arg2
Jacob Kaniuk
  • 175
  • 6
  • Thank you a lot, i was thinking about converting this into oop but thought i can solve this without it. Anyway, thanks again! – Denya56 Aug 05 '20 at 19:06
  • Just one more thing, i can't get how this works:```src = sys.argv[1] if os.path.exists(sys.argv[1]) else os.path.join('D', 'py') dst = sys.argv[2] if os.path.exists(sys.argv[2]) else os.path.join('D', 'Backup')``` – Denya56 Aug 05 '20 at 19:30
  • It's an `if/else` statement written in one line. It's basically saying if there aren't any arguments provided when calling the script, use the "default" values instead. `os.path.join` is just a function used to build a filepath (not super important to use it in this case, but definitely good practice to always use it when possible.) – Jacob Kaniuk Aug 06 '20 at 05:41
  • `sys.argv` is just a list of arguments that were used when calling the script you're running. `sys.argv[0]` is the name of the script `sys.argv[1]` is the **1st** argument in a call `sys.argv[2]` is the **2nd** argument in a call if you call `/mnt/c/py/my_test_script 15 /mnt/c/py /mnt/c/backup` `sys.argv[0]` = `/mnt/c/py/my_test_script` `sys.argv[1]` = `15` `sys.argv[2]` = `/mnt/c/py` `sys.argv[3]` = `/mnt/c/backup` You should look into `ArgumentParser` in the `argparse` module. Has more features and does a lot of these sorts of things for you fairly simply. – Jacob Kaniuk Aug 06 '20 at 05:42
  • Also, if you found the answer useful and end up using it, mark the answer as the answer to your question. – Jacob Kaniuk Aug 06 '20 at 05:48
  • Ok, got it. I'm running windows so i can change it just to whatever path i want. – Denya56 Aug 06 '20 at 06:44
  • I have another question: if i run the program (delay for 1 hour) after 10 min i turn off my computer. Turn on after 20 min so the code have to be executed after 30 min now. I was thinking how to do this and came up with an idea to do it with file where I'll write time destination and when running program I'll check if there any text in the file. If True so it will count the difference between date in file and current date. Again when using datetime module i came up with a problem: i can write only str obj but i can't convert it back to datetime obj which is required – Denya56 Aug 06 '20 at 06:45
  • You're making it too complicated for yourself. If you're on windows, the easiest thing for you to do is create a task for this in the windows tool `Task Scheduler`. Use the first code I gave you and save it to a file `backup_archive` somewhere, and add a task which launches that script. Provide it the 2 arguments (source path, dest path) and set it to repeat every 5 minutes indefinitely. Doing it this way will also allow you to easily add more backup instances for different directories just by creating a new task and providing new args (directories). – Jacob Kaniuk Aug 06 '20 at 15:44
  • https://www.windowscentral.com/how-create-automated-task-using-task-scheduler-windows-10 Go to the section `How to create an advanced task using Task Scheduler` – Jacob Kaniuk Aug 06 '20 at 15:45
  • OK, understad! Thanks – Denya56 Aug 06 '20 at 16:42