Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonadventurer committed Apr 17, 2023
0 parents commit 59ee6b9
Show file tree
Hide file tree
Showing 12 changed files with 901 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.pyc
*.bat
env/
__pycache__/
private/

7 changes: 7 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# PyBackup Change Log

Rob Fowler <[email protected]>

## 0.0.1 - YYYY-MM-DD


674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Py Backup - A simple personal backup utility
*v0.0.1*

Updated: 2023-04-17

## Introduction

**PyPackup** is a simple, no-frills, easy to use personal file backup app.

## Features
- Backup to a timestamped *.zip file.
- Save backup sources and destinations for easy re-use.

## License
GNU General Public License 3. See the LICENSE file for details.

## Installation
- Written in Python 3.11 on Windows 11. Not tested in any other Python versions or operating systems. I'm confident it can be made to work on Mac and Linux.
- Has no requirements outside the Python standard library.
- Download the repo as a zip file and extract.
- ``python backup.py`` to launch.

## Confguration
- Saved backups are contained in the file ``backups.json``.

## Screenshot
![](screenshot.jpg)

## Documentation
- Click the **Select Source** button to choose a directory to back up.
- Click the **Select Destination** button to choose a directory to back up to. A time-stamped ZIP file will be created in this folder.
- Click **Run Now** to execute the backup. A pop up will notify when the backup is completed.
- Click **Save Backup** to save the backup configuration for later use. The backup will appear by name in the **Select Saved Backup** drop down list. You will need to re-start PyBackup for new backups to appear on this list.
- To load a saved backup, click on the **Select Saved Backup** drop down list and select the name of the desired backup. The source and destination boxes will populate from the saved backup. You can then click **Run Now** to execute the saved backup.

## Credit
3 changes: 3 additions & 0 deletions app.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
root - WARNING - This is a warning message
root - ERROR - This is an error message
root - CRITICAL - This is a critical message
9 changes: 9 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from tkinter import *
from tkinter import ttk
from backup import *
from gui import *

root = Tk()
PyBackup(root)
root.mainloop()

41 changes: 41 additions & 0 deletions backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from pathlib import Path
import configparser
import json
import zipfile
import datetime as dt

def zip_backup(source,dest):
source = Path(source)
timestamp = str(dt.datetime.now()).replace(" ","-").replace(":","")[:17]
dest = Path(dest,timestamp)


print(f"Backing up {source} to {dest}....")
with zipfile.ZipFile(dest, mode="w") as archive:
for file_path in source.rglob("*"):
archive.write(file_path,
arcname=file_path.relative_to(source))
print("Backup completed.")

def save_backup(source,dest,name):
with open("backups.json","r",encoding="utf-8") as f:
saved_backups = json.load(f)
saved_backups[name] = {}
saved_backups[name]["source"]=source
saved_backups[name]["dest"]=dest

with open("backups.json","w",encoding="utf-8") as f:
json.dump(saved_backups,f)

def load_backup(name):
with open("backups.json","r",encoding="utf-8") as f:
saved_backups = json.load(f)
return saved_backups[name]

def delete_backup(name):
with open("backups.json","r",encoding="utf-8") as f:
saved_backups = json.load(f)
n = saved_backups.pop(name)
with open("backups.json","w",encoding="utf-8") as f:
json.dump(saved_backups,f)

1 change: 1 addition & 0 deletions backups.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"backend": {"source": "//server/Access/Backend_v2", "dest": "F:/backend"}, "documents": {"source": "C:/Users/Robf.DESKTOP-JNCQ9MB/Documents", "dest": "F/documents"}, "devnotes3": {"source": "C:/Users/Robf.DESKTOP-JNCQ9MB/Documents/DevNotes3", "dest": "F:/devnotes"}}
114 changes: 114 additions & 0 deletions gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from pathlib import Path
from backup import *

import json


class PyBackup:
def __init__(self,root):
root.title("PyBackup")
mnuMain = MainMenu(root)
root.config(menu=mnuMain)
Main = MainFrame(root)

class MainMenu(Menu):
def __init__(self,root):
Menu.__init__ (self,root)

mnuFile = Menu(self,tearoff=0)
self.add_cascade(label="File",menu=mnuFile)
mnuFile.add_command(label="Quit",command=root.quit)

mnuEdit = Menu(self,tearoff=0)
self.add_cascade(label="Edit",menu=mnuEdit)
mnuEdit.add_command(label="Preferences")

mnuHelp = Menu(self,tearoff=0)
self.add_cascade(label="Help",menu=mnuHelp)
mnuHelp.add_command(label="About")

class MainFrame(Frame):
def __init__(self,parent):
Frame.__init__ (self,parent)

global varSaveBackup

# Load list of saved backups
with open("backups.json","r",encoding="utf-8") as f:
saved_backups = json.load(f)

backups_list = list(saved_backups.keys())

def SelectSource():
varSource.set(filedialog.askdirectory(title = "Select Source Folder"))

def SelectDestination():
varDest.set(filedialog.askdirectory(title = "Select Destination Folder"))

def RunNow():
zip_backup(varSource.get(), varDest.get())
messagebox.showinfo("PyBackup","Backup complete.")

def SaveBackupPopup():
Popup = Toplevel(parent)

def SaveBackupName():
varSaveBackup = txtValue.get()
save_backup(varSource.get(),varDest.get(),varSaveBackup)
Popup.destroy()

def Cancel():
Popup.destroy()

lblEntry = Label(Popup,text="Enter a name for this backup:",font=("Helvetica",10))
txtValue = Entry(Popup, font=("Helvetica",10))
btnOK = Button(Popup,text="OK",width=10,command=SaveBackupName)
btnCancel= Button(Popup,text="Cancel",width=10,command=Cancel)

lblEntry.grid(row=0,column=0,columnspan=2,padx=10,pady=5)
txtValue.grid(row=1,column=0,columnspan=2,padx=5,pady=5)
btnOK.grid(row=2,column=0,sticky=(W,E),padx=5,pady=5)
btnCancel.grid(row=2,column=1,sticky=(W,E),padx=5,pady=5)



def LoadBackup(e):
backup = load_backup(varSavedBackup.get())
varSource.set(backup['source'])
varDest.set(backup['dest'])


# create widgets
varSource=StringVar()
btnSource = Button(self,text="Select Source",command=SelectSource)
txtSource = Entry(self, textvariable=varSource,font=("Helvetica",10),width=30)

varDest=StringVar()
btnDest = Button(self,text="Select Destination",command=SelectDestination)
txtDest = Entry(self, textvariable=varDest,font=("Helvetica",10),width=50)

btnRunNow = Button(self,text="Run Now",command=RunNow)
btnSaveBackup = Button(self,text="Save Backup",command=SaveBackupPopup)

lblSelectSaved = Label(self,text="Select Saved Backup",font=("Helvetica",10))

varSavedBackup = StringVar()
cboSelectSaved = ttk.Combobox(self,textvariable=varSavedBackup,font=("Helvetica",10))
cboSelectSaved['values'] = backups_list
cboSelectSaved.bind("<<ComboboxSelected>>",LoadBackup)

# grid the widgets
btnSource.grid(row=0,column=0,sticky=(W),padx=5,pady=5)
txtSource.grid(row=1,column=0,sticky=(W,E),padx=5,pady=5,columnspan=2)
btnDest.grid(row=2,column=0,sticky=(W),padx=5,pady=5)
txtDest.grid(row=3,column=0,sticky=(W,E),padx=5,pady=5,columnspan=2)
btnRunNow.grid(row=4,column=0,padx=5,pady=5)
btnSaveBackup.grid(row=4,column=1,padx=5,pady=5)
lblSelectSaved.grid(row=5,column=0,padx=5,pady=5,columnspan=2)
cboSelectSaved.grid(row=6,column=0,padx=5,pady=5,columnspan=2)

self.grid(row=0,column=0,sticky=(W,E))
10 changes: 10 additions & 0 deletions logtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import logging


logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s')

logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')
Binary file added requirements.txt
Binary file not shown.
Binary file added screenshot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 59ee6b9

Please sign in to comment.