Tag: Python

Backup File Utility in Python [Tkinter application]

Hi readers,

This is a graphic software (tkinter) in Python to back up a file on your computer. A backup folder is created in the current directory of the selected file and then every x minutes a backup of the file is done, respecting the maximum number of files in the backup directory.

backup_app

 

backup_app_dir

 

import xxhash, time, shutil, os, threading
from datetime import datetime
from Tkinter import Label, Spinbox, Listbox, Scrollbar, Tk, E, W, S, N, Button, Frame
import tkFileDialog
from os.path import expanduser

class App(Frame):
    def __init__(self, parent):

        Frame.__init__(self, parent)
        self.parent = parent

        # Class Variables
        self.directory_selected = ''
        self.filename_selected = ''
        self.backup_folder_name = 'backup'
        self.num_max_files = None
        self.time_for_backup = None
        self.full_file_path = ''
        self.backup_running = False
        self.hash = None

        self.initUI()

    def initUI(self):
        self.parent.title("Application to Backup a File")

        self.label_minutes = Label(text='Time for Backup (Minutes): ', height=2)
        self.spinbox_minutes = Spinbox(from_=1, to=100, width=5)
        self.spinbox_minutes.delete(0, 'end')
        self.spinbox_minutes.insert(0, 5)

        self.label_numfiles = Label(text='Maximum number files in backup directory: ')
        self.spinbox_numfiles = Spinbox(from_=1, to=100, width=5)
        self.spinbox_numfiles.delete(0, 'end')
        self.spinbox_numfiles.insert(0, 10)

        self.scrollbar_loglist = Scrollbar()
        self.listbox_loglist = Listbox(yscrollcommand=self.scrollbar_loglist.set, width=70)
        self.scrollbar_loglist.config(command=self.listbox_loglist.yview)

        self.button_file_choose = Button(text='Choose a file for backup ...', command=self.click_button_start_backup)
        self.button_stop_backup = Button(text='Stop Backup', command=self.click_button_stop_backup)
        self.button_stop_backup['state'] = 'disabled'
        self.button_exit = Button(text='Exit', command=self.click_button_exit)

        # Here the UI components are designed using grid layout
        self.label_minutes.grid(row=0, sticky=E)
        self.spinbox_minutes.grid(row=0, column=1, sticky=W)
        self.label_numfiles.grid(row=1, sticky=E)
        self.spinbox_numfiles.grid(row=1, column=1, sticky=W)
        self.listbox_loglist.grid(row=2, column=0, sticky=W + E + N + S, columnspan=3)
        self.scrollbar_loglist.grid(row=2, column=3, sticky=N + S)
        self.button_file_choose.grid(row=3, column=0)
        self.button_stop_backup.grid(row=3, column=1)
        self.button_exit.grid(row=3, column=2)

        # define options for opening or saving a file
        self.file_opt = options = {}
        options['initialdir'] = expanduser("~")
        options['parent'] = self
        options['title'] = 'Select a file for backup ...'

    def get_ask_open_file(self):
        return tkFileDialog.askopenfilename(**self.file_opt)

    def get_current_datetime(self):
        return datetime.strftime(datetime.now(), "%d%m%Y_%H%M%S")

    def get_current_datetime_formatted(self):
        return datetime.strftime(datetime.now(), "[%d/%m/%Y %H:%M:%S] - ")

    def log_action(self, msg):
        self.listbox_loglist.insert(0, self.get_current_datetime_formatted() + msg)

    def do_file_backup(self):
        curr_datetime = self.get_current_datetime()
        nom_arquivo = self.filename_selected.split('.')[0] + '_' + curr_datetime + '.' + \
                      self.filename_selected.split('.')[1]
        shutil.copyfile(self.full_file_path,
                        self.directory_selected + os.sep + self.backup_folder_name + os.sep + nom_arquivo)
        self.log_action('Backup Done - ' + nom_arquivo)

    def get_file_hash_md5(self, file):
        BLOCKSIZE = 65536
        hasher = xxhash.xxh32()
        with open(file, 'rb') as afile:
            buf = afile.read(BLOCKSIZE)
            while len(buf) > 0:
                hasher.update(buf)
                buf = afile.read(BLOCKSIZE)
        return hasher.hexdigest()

    def listdir_fullpath(self, d):
        return [os.path.join(d, f) for f in os.listdir(d)]

    def delete_oldest_files(self):
        num_total_files_in_directory = len(
            self.listdir_fullpath(self.directory_selected + os.sep + self.backup_folder_name))
        num_files_to_be_removed = num_total_files_in_directory - self.num_max_files
        if num_files_to_be_removed > 0:
            self.log_action('Removing ' + str(num_files_to_be_removed) + ' old files')
        for i in range(num_files_to_be_removed):
            file_to_remove = self.get_oldest_file_from_directory(
                self.directory_selected + os.sep + self.backup_folder_name)
            os.remove(file_to_remove)
            self.log_action('An old file was removed - ' + file_to_remove.split(os.sep)[-1])

    def get_oldest_file_from_directory(self, dir):
        return min(self.listdir_fullpath(dir), key=os.path.getctime)

    def start_loop_backup_job(self):
        if not self.backup_running:
            return
        self.delete_oldest_files()
        if self.hash != self.get_file_hash_md5(self.full_file_path):
            self.do_file_backup()
        else:
            self.log_action('The file was not changed since last check')
        self.hash = self.get_file_hash_md5(self.full_file_path)
        self.parent.after(self.time_for_backup * 1000 * 60, self.start_loop_backup_job)

    def click_button_start_backup(self):
        file_choosed = self.get_ask_open_file()
        if not os.path.isfile(file_choosed):
            return
        self.log_action('Backup has been started')
        self.backup_running = True
        self.button_file_choose['state'] = 'disabled'
        self.button_stop_backup['state'] = 'normal'
        self.directory_selected = os.path.split(os.path.abspath(file_choosed))[0]
        self.filename_selected = os.path.split(os.path.abspath(file_choosed))[1]
        self.full_file_path = self.directory_selected + os.sep + self.filename_selected

        if not os.path.exists(self.directory_selected + os.sep + self.backup_folder_name):
            os.mkdir(self.directory_selected + os.sep + self.backup_folder_name)

        self.time_for_backup = int(self.spinbox_minutes.get())
        self.num_max_files = int(self.spinbox_numfiles.get())

        self.backup_running = True
        self.start_loop_backup_job()

    def click_button_stop_backup(self):
        self.button_file_choose['state'] = 'normal'
        self.button_stop_backup['state'] = 'disabled'
        self.log_action('Backup has been stopped')
        self.backup_running = False

    def click_button_exit(self):
        self.parent.destroy()

def main():
    root = Tk()
    root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
    app = App(root)
    root.mainloop()

if __name__ == '__main__':
    main()

 

Python – Unique Collection Class – HashCode and Equals – (Like Java Set)

Hi readers,

I will demonstrate in this post as we do in Python to have a collection of single objects (Set), implementing the standard methods key, hashcode and equals, so that the objects are not repeated.

class MyCustomClass:
    def __init__(self, at1, at2, at3):
        self.at1 = at1
        self.at2 = at2
        self.at3 = at3
    def __key(self):
        return (self.at2)
    def __eq__(x, y):
        return x.__key() == y.__key()
    def __hash__(self):
        return hash(self.__key())

my_object_1 = MyCustomClass('1', '2', '3')
my_object_2 = MyCustomClass('4', '5', '6')
my_object_3 = MyCustomClass('7', '8', '9')
my_object_2_dup = MyCustomClass('4', '5', '6')

set_collection = set()

set_collection.add(my_object_1)
set_collection.add(my_object_2)
set_collection.add(my_object_3)
set_collection.add(my_object_2_dup)

for object in set_collection:
    print object.at2

The output of this script is:
8
2
5

Note that i added 4 objects, but only three is added because the second attribute is the Key.

See You,
Victor Jabur

Compiling MySQLdb 1.2.3 on Windows 32 and 64 – Without need the MySQL Database 5.5 installed

Hi,

If you wish the module already compiled, access here: http://blog.victorjabur.com/2011/06/08/modules-python-library-compiled-for-windows-32-and-64-unofficial-windows-binaries-for-python/

First Thing: Follow this main steps to prepare the pre-requirements for compile this module:

http://blog.victorjabur.com/2011/06/05/compiling-python-2-7-modules-on-windows-32-and-64-using-msvc-2008-express/

1 – Compiling MySQLdb 1.2.3 for Mysql 5.5 database

1.1 – You will need to download the latest version of MySQL Connector C here: http://dev.mysql.com/downloads/connector/c/

* Important: Make the download properly for your platform (32 or 64 bits).

1.2 – Make the download of MySQLdb plugin here and extract to any folder: http://sourceforge.net/projects/mysql-python/

1.3 – Edit this file (MySQL-python-1.2.3/setup_windows.py) inside of folder extracted:

At Line 7 of the file, comment the two follow lines and add another, like this:

    #serverKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, options['registry_key'])
    #mysql_root, dummy = _winreg.QueryValueEx(serverKey,'Location')
    mysql_root = ''

At Line 19, put the path to your Connector C installed:

    library_dirs = [ os.path.join(mysql_root, r'lib\opt'), 'C:\Program Files\MySQL\MySQL Connector C 6.0.2\lib\opt' ]
    libraries = [ 'kernel32', 'advapi32', 'wsock32', client ]
    include_dirs = [ os.path.join(mysql_root, r'include'), 'C:\Program Files\MySQL\MySQL Connector C 6.0.2\include' ]
    extra_compile_args = [ '/Zl' ]

Important: Specify the correct path for your platform (32 or 64 bits). Above the platform is 64 bits, to 32 bits use this path: “C:\Program Files (x86)\MySQL\MySQL Connector C 6.0.2”.

1.4 – Make the build:

python setup.py build --compiler msvc
python setup.py bdist_wininst

It’s finish.

The advantage os this technique an a comparison with others posts is:

1 – The MySQL Database is not required on machine (only the connector c)
2 – Not is necessary make the update on the windows registry:

# The Windows registry key for MySQL.
# This has to be set for Windows builds to work.
# Only change this if you have a different version.
registry_key = SOFTWARE\MySQL AB\MySQL Server 5.0

Credits and References to this post:

http://chaos.weblogs.us/archives/327
http://www.fuyun.org/2009/12/install-mysql-for-python-on-windows/

Bye,
Victor Jabur

Material para Estudo Python

Oi Pessoal,

Gostaria de indicar a vocês alguns materiais para estudo da linguagem Python:

1) Livro traduzido por um projeto bancado pela Fapesp: http://code.google.com/p/aprendacompy/
2) Livro para desenvolvedores (mais avançado): http://ark4n.wordpress.com/python/
3) Este é o mais legal: http://people.csail.mit.edu/pgbovine/python – Uma aplicação online, através da qual você consegue rodar código python online. Passo a passo e com debug.
E ainda vem com alguns scripts pré prontos como Fibonacci, Fatorial e etc …

Abraços !
Victor Jabur

Instalar MySQL para Python (MySQLdb) em Windows

Atualização (08/06/2011):

Acessar este outro post: http://blog.victorjabur.com/2011/06/08/compiling-mysqldb-1-2-3-on-windows-32-and-64-without-need-the-mysql-database-5-5-installed/

————————————————————————————————————-

Solução 1 – Instalação através de arquivos Egg

1 – Passos para instalar o setuptools, se você ainda não tiver instalado:

  1. Instalar o Setup Tools do Python (Instalador de pacotes em Python) – Download Aqui
  2. Incluir na sua Variável de Sistema PATH, o seguinte diretório: “C:\Python27\Scripts”
  3. Incluir na sua Variável de Sistema PATH, o seguinte diretório: “C:\Python27”

2 – Fazer o download dos arquivos egg abaixo, de acordo com sua versão de python e sistema operacional:

Versões para MySQLdb 1.2.3 e Windows 32 bits

MySQL_python-1.2.3-py2.6-win32.egg
MySQL_python-1.2.3-py2.7-win32.egg

Versões para MySQLdb 1.2.3 e Windows 64 bits:

(Em breve)

3 – Abrir um command DOS, acessar a pasta no qual os arquivos egg se encontram e executar o seguinte comando e pronto !

easy_install MySQL_python-1.2.3-py2.6-win32.egg
ou
easy_install MySQL_python-1.2.3-py2.7-win32.egg

—————————————————————————————–

Solução 2 – Alguns arquivos binários (.exe) que encontrei na web.

http://www.codegood.com/archives/4

—————————————————————————————–

Solução 3 – Preparando seu ambiente para compilar código fonte C, com esta opção você será capaz de compilar qualquer código pthon necessário para o MySQLdb e outros plugins. (um pouco trabalhoso).

O MySQLdb é um pacote desenvolvido em python, que possibilita o acesso ao banco de dados MySQL.

A missão deste post é ensinar como instalar o MySQLdb, em um ambiente Windows:
Este pacote não possui arquivo binário para instalação em um ambiente Windows, conforme a própria documentação nos diz:

Windows
…….
I don’t do Windows. However if someone provides me with a package for
Windows, I’ll make it available. Don’t ask me for help with Windows
because I can’t help you.

Portanto, será necessário compilar o código fonte em C, para só então conseguir instalar o MySQLdb.

Se fosse em Linux, Ubuntu, por exemplo, este pacote seria instalado com um simples comando: apt-get install python-mysqldb

Mas em Windows dá um trabalhinho, vamos ao trabalho:

1 – Pré-Requisitos:

  • Instalar o Microsoft Visual C++ Express Edition 2010 – Download Aqui (Algumas pessoas relatam que conseguiram compilar com o Cygwin e o Mingw, mas eu não consegui)
  • Ter o python instalado – Download Aqui
  • Ter o banco de dados MySQL instalado – Download Aqui
    • Importante: Selecionar para instalação a opção: Developer Components (Custom Setup), se você já tem o banco instalado, pode instalar este item como adicional, sem problemas.
  • Após Instalar o Microsoft Visual C++ Express Edition 2010, criar uma variável de ambiente:
    1. Botão Direito do Mouse em cima de “Meu Computador” -> Propriedades -> Avançado -> Variáveis de Ambiente -> Nova
    2. Nome da Variável: VS90COMNTOOLS
    3. Valor da Variável: C:\Arquivos de programas\Microsoft Visual Studio 10.0\Common7\Tools\ (Coloque o seu caminho de instalação, se for diferente deste)
  • Instalar o Setup Tools do Python (Instalador de pacotes em Python) – Download Aqui
  • Incluir na sua Variável de Sistema PATH, o seguinte diretório: “C:\Python27\Scripts”
  • Incluir na sua Variável de Sistema PATH, o seguinte diretório: “C:\Python27”
  • Fazer o download do MySQLdb aqui: Download Aqui e descompactar em qualquer diretório
  • Editar o arquivo site.cfg (na pasta descompactada), para a sua versão de banco de dados MySQL, escolha uma das opções abaixo:
    • “registry_key = SOFTWARE\MySQL AB\MySQL Server 5.0”
    • “registry_key = SOFTWARE\MySQL AB\MySQL Server 5.1”

2 – Instalando:

  1. Abrir um prompt do Dos
  2. Acessar a pasta descompactada (Comando cd)
  3. Executar o comando: setup.py build (Não deve aparecer nenhuma mensagem de erro)
  4. Executar o comando: setup.py install
  5. Abrir o Shell do Python e testar se a instalação funcionou, digitando o seguinte comando: import MySQLdb
    • Se funcionar não aparecerá mensagem nenhuma
    • Em caso de erro, aparecerá algo do tipo:
    • Traceback (most recent call last):
      File “”, line 1, in
      ImportError: No module named “pacote”

Créditos deste Post ao Yun Fu: http://www.fuyun.org/2009/12/install-mysql-for-python-on-windows/

Bom Pessoal, vou ficar por aqui, espero que vocês consigam instalar, apanhei bastante e por isso resolvi fazer este post.

Até a Próxima.

Victor Jabur

Instalando e Configurando Plugin Python no Eclipse (Pydev)

Sejam Bem Vindos,

Neste post estou ensinando como instalar e configurar um ambiente para a programação da linguagem Python na IDE Eclipse:

Segue o link para download do Python:
http://www.python.org/download/

1- Download do Eclipse:
http://www.eclipse.org/downloads
2- Selecione o menu help -> Install New Software …
3- Clicar no botão Add
4- Preencher com as seguintes informações:
Name: Pydev
Location: http://pydev.org/updates/
5- Selecionar apenas a opção PyDev e clicar em Next
6- Clicar em Next
7- Aceitar a licença e clicar em Finish
8- Aceitar a mensagem e clicar em OK
9- Selecionar o checkbox e clicar no botão OK (Aceitar o certificado)
10- Clicar no botão Yes para reiniciar o Eclipse
11- Assim que o Eclipse reiniciar, acessar Window -> Preferences
12- Acessar a opção Python -> Interpreter-Python e clicar no botão New
13- Clicar no botão Browse e informar o caminho onde o Python está instalado
14- Escolher o arquivo python.exe (para windows) ou opção similar para demais sistemas operacionais
15- Clicar no botão OK
16- Confirmar com o botão OK
17- Clicar OK Novamente
18- Pronto ! Agora o seu Eclipse já pode usar todos os recursos do plugin Pydev. Tais como Debug, AutoCompletar, Criação de Projetos e etc …
19- Vamos experimentar alguns destes recursos, criando um projeto exemplo.
20- Clique em File -> New -> Project
21- Selecione Pydev -> Pydev Project, clique em Next
22- Deixe as configurações conforme tela abaixo e clique em Finish
23- Clique em Yes para acessar a Perspectiva para programação em Python no Eclipse
24- Clique com o botão direito do mouse sobre a pasta src e selecione New -> Pydev Module
25- Segue abaixo um código que atribui uma string Hello World a uma variavel e depois imprime na tela
26- Segue abaixo a utilização do recurso AutoCompletar
27- Segue abaixo um exemplo de Debug, colocando um breakpoint e rodando o debug através de Debug As -> Python Run
28- Observe abaixo o exemplo de Debug
29- Para aqueles que ficaram curiosos em relação à mensagem em vermelho na imagem acima, vou explicar:
Existe um plugin para debug na linguagem python, chamado psyco, responsável por acelerar o processo de Debug, para aqueles que quiserem instalar (é opcional), segue o link para download:

http://psyco.sourceforge.net/download.html

30- É isto pessoal, espero ter ajudado com este post e até a próxima …