🤔 Para Refletir :
"Números são apenas números, não estrague seu dia por causa deles."
- Ricky O Bardo

Python - Criando um updater, parte 1

HermesPasser Masculino

Duque
Membro
Membro
Vícios e amores servem para preencher o vazio
Juntou-se
23 de Março de 2017
Postagens
836
Bravecoins
92
Introdução
Com este projeto planejo fazer um updater, ou seja, um utilitário que atualiza o seu programa em Python. Pessoalmente eu não tenho tanta familiaridade com essa linguagem então estarei aprendendo junto vocês

Esse tutorial será dividido em partes que serão lançadas irregularmente.

Funcionamento

Esse projeto funcionará da seguinte maneira:
  • Um documento XML online que será acessado para buscar as informações;
  • Um arquivo .zip com os arquivos que serão baixados para servir como atualização;
  • O nosso projeto em python que acessará o XML, deletará e atualizará (baixando o .zip) os arquivos listados lá.

O XML consiste de um nó principal, que chamarei de ventura (pois este é o nome que escolhi para o projeto, entendedores entenderão) e dentro terá os nós update que contém o atributo com a versão e os nós com o link de download (url) para a atualização e um com a lista de pastas e arquivos a serem deletados (delete). As pastas/arquivos serão separados por uma virgula e serão consideradas pastas nomes com uma barra inversa "/" no final.

Código:
<?xml version="1.0" encoding="UTF-8"?>
<ventura>
  <update version="0.1">
    <url>https://um.link</url>
    <delete>file_to_delete1.txt,folder1\</delete>
  </update>
</ventura>

Preparativos

Precisaremos, claro, do Python. No caso eu estou usando o Python 3.6.1 mas você pode clicar aqui para baixar a última versão disponível. Só tenha em mente que o Python muda consideravelmente de uma principal versão para outra

Depois, tenha certeza de criar o seu documento XML e hospeda-lo em um lugar que permita você acessa-lo diretamente (assim), para isso estarei usando o Gist GitHub mas creio que o Pasterbin e genéricos permitam você fazer o mesmo.

Igualmente precisará de acesso direto (link direto) ao .zip que terá que hospedar. Isso pode ser obtido com o Dropbox/Google Drive/Microsoft Drive deixando o arquivo publico, estarei usando o GitHub para isso já que tenho um .zip de outro projeto que armazenado (veja o arquivo / link direto do arquivo) que será o que usarei.

Com isso, nossas preparações estão completas. Let's Code!

1º Passo - Main & Zip

Antes de qualquer coisa digo que tenho a convenção de colocar "h" antes do nome dos arquivos que tenham nome comum pois me já aconteceu de haver colisões entre meus módulos (nome bonito para arquivo) e os do Python.

Começaremos criando a rotina para extrair o arquivo .zip: Crie a pasta de seu projeto e os arquivos main.py (que será o ponto de entrada do programa) e hzip.py (responsável pela rotina de extração).

Em hzip importe zipfile, modulo que manipula arquivos .zip e os, que são diversas interfaces com o sistema operacional.

Código:
import zipfile
import os

Logo em seguida criaremos a única função desse arquivo, extract, que receberá dois argumentos; um com o local do arquivo .zip e outro com o local onde será extraído:

Código:
def extract(file_url, path_to_extract):
	# carrega o arquivo .zip especificado 
	zip_file = zipfile.ZipFile(file_url, 'r')
	# extrai o conteudo do .zip
	zip_file.extractall(path_to_extract)
	# fecha o arquivo (no caminho especificado) e libera os recursos usados
	zip_file.close()
	# apaga o arquivo
	os.remove(file_url)

No main vamos importar o nosso hzip:

Código:
import hzip

Agora você pode fazer um teste para verificar se está funcionando colocando um arquivo .zip na mesma pasta e adicionando o seguinte código:

Código:
# extrai o "arquivo".zip na pasta onde está o arquivo.
hzip.extract('arquivo.zip', '')
Para executar, abra o cmd/powershell na pasta do projeto (simplesmente digite cmd ou powershell na barra de endereço do explorer e tecle enter) e escreva python main.py e veja a mágica sendo feita.

Agora vamos adicionar a função main e adicionar isso dentro (note que mudei o nome do arquivo para um que seja mais coerente, será esse o nome com qual salvaremos o arquivo da internet):

Código:
def main():
	hzip.extract('update.zip', '')

# Só executa se o arquivo for chamado diretamente ao invés de importado.
if __name__ == '__main__':
	main()

2º Passo - Path

Agora criaremos um arquivo para com as rotinas de manipulação de arquivos, o chamarei de hpath.py.

Iniciemos importando pathlib, para operações com diretórios, shutil, para operações com arquivos e a já conhecida os:

Código:
import pathlib
import shutil
import os

Agora criemos a função para criar uma pasta, passando o caminho (+ nome dela) por parâmetro:

Código:
def create_dir(dir):
	# dir recebe o nome da pasta, sou seja se for passado "pasta1\pasta2" então ele receberá "pasta2"
	dir = os.path.dirname(dir)
	# retorna se a pasta não possuir nome
	if dir == '':
		return
	# cria um objeto do tipo path passando o nosso paramêtro (e deixa no formato adequado para o sistema)
	path = pathlib.Path(dir)
	# cria a pasta, os parâmetros dizem criar as subpastas e para não fazer nada se ela existir (ou caso jogaria uma exceção)
	path.mkdir(parents = True, exist_ok = True)

Agora vamos criar a função que verifica se é um arquivo ou uma pasta, recebendo o parâmetro da string a ser verificada:

Nota: o Python tem funções que fazem isso mas elas funcionam somente com o caminho absoluto, mas ela não convém aqui mesmo se não fosse o caso já que nós definimos que queremos que ele considere pasta uma string que contenha uma barra inversa no final, então convém criarmos essa função.

Código:
def is_folder(text):
	# retorna verdadeiro se o texto acaba com uma barra inversa e falso se não
	return text.endswith("\\")

Agora adicionaremos as duas funções que se encarregarão de apagar pastas e arquivos, passando uma string em cada um representando a pasta/arquivo:

Código:
def remove_file(file):
	# verifica se o arquivo existe
	if os.path.isfile(file):
		# apaga o arquivo
		os.remove(file)
		
def remove_folder(folder):
	# verifica se a pasta existe
	if os.path.isdir(folder):
		# apaga a pasta (mesmo com arquivos dentro)
		shutil.rmtree(folder)

E por fim, a função que receberá um array de nomes de arquivos e pasta a serem apagados, darei o nome de delete_files (não confundam com o remove_file que apaga um arquivo):

Código:
def delete_files(files):
	# navega em cada item de files usando file para representar o valor atual
	for file in files:
		# verifica se o valor é uma pasta (função explicada anteriormente)
		if is_folder(file):
			# chama a função que remove pastas para apagá-lo
			remove_folder(file)
		else:
			# chama a função que remove arquivos para apagá-lo
			remove_file(file)

Aftermath

Irei parar por aqui pois o tópico já está ficando grande. Espero que gostem, até a parte dois.



Parte I • Parte II • Introdução

E cá estamos na última parte \o/. Espero que isso tenha ajudado você a entender melhor como o Python funciona, pois me ajudou. Sem mais delongas:

4º Passo - Package

Agora vamos transformar esse projeto em um package para que ele possa ver usado por outros projetos. Primeiro renomeie o arquivo main para o nome que queres para seu projeto (pois não faz sentido alguém importar o main), o eu será ventura. Depois adicione o nome do projeto (o da pasta) antes do nome de cada importação que fizemos de nossos arquivos. Isso será necessário para que eles possam ser importados mesmo que o caminho onde o programa está rodando é outro. Também remova o import do sys pois não usaremos mais argumentos de linha de comando.

Outra coisa que faremos é adicionar "_" no nome de cada arquivo exceto o mais para que o usuário saiba que esses arquivos não foram projetados para serem usados por eles.

Note que a importação do _hxml não tem "ventura." pois nesse caso só um ponto basta.

ventura.py (antigo main.py)
Código:
from ._hxml import VenturaXML
import ventura._hzip as hzip
import ventura._hweb as hweb
import ventura._hpath as hpath
 

_hpath.py (antigo hpath.py)
Código:
import ventura._hpath as hpath

Agora crie um arquivo chamado __init__.py, este arquivo não precisa conter nada dentro, ele serve para que o diretório seja considerado um package.

Parabéns! Você criou um package, tente adicionar a pasta dele em seu projeto e importa-lo em um arquivo seu (exemplo: import ventura).

5º Passo - Publicação

Agora prepararemos para que este package possa ser publicado [url=https://pypi.org]PyPI
, o lugar onde armazena-se packages para que sejam baixados. Mas especificamente publicaremos no Test PyPI, subdomínio para testes. Eu me basearei neste tutorial.

Crie uma subpasta com o nome do projeto e mova todos os arquivos para lá, mas fique na pasta onde está pois nela que criaremos os próximos arquivos que precisamos para publicar o projeto.

Aqueles acostumados com git entenderão bem o que faremos em seguida: crie README.md, LICENSE (arquivo sem extensão) e .gigignore (arquivo sem o nome). No README escreva uma descrição do projeto (aprenda aqui), em LICENSE, a licença (que no meu caso usei a MIT, ela é só um arquivo de texto normal), o gitignore é onde você escreverá todas as pastas e arquivos que serão ignorados na hora de subir o projeto para o repositório (saiba como).

O próximo arquivo que criaremos é o setup.py, este é o responsável por armazenar informações do projeto. Abaixo deixarei um modelo (que não tem todas as informações possíveis mas tem as essenciais).

Código:
from setuptools import setup

# o método que será chamado pelo "empacotador"
setup(
      # nome do pacote
      name = 'ventura',
      # versão do pacote
      version = '0.1',
      # uma descrição, existe um descrição mais completa que podemos fazer em formato 
      #markdown usando o texto do README mas não usaremos
      description = 'Simple xml-based updater in python 3.6 with no try-catch statement',
      # link do projeto, geralmente o repositório do projeto. 
      url = 'http://github.com/hermespasser/ventura',
      # nome do autor
      author = 'Hermes Passer',
      # email do autor
      author_email = 'hermespasser@gmail.com',
      # a licença escolhida para o projeto
      license = 'MIT',
      # os pacotes inseridos, ou coloque o mesmo valor que colocou em name ou você pode 
      # procurar dinamicamente importando o find_packages() do setuptools
      packages = ['ventura']
)

Agora vamos iniciar o processo de criar a distribuição e enviar. Rode python -m pip install --user --upgrade setuptools wheel só para ter certeza que o setuptools e wheel estão instalados e devidamente atualizados.

Agora vamos efetivamente criar a distribuição, para isso devemos está na mesma pasta que o setup.py está instalado. Rode python setup.py sdist bdist_wheel e será criada a pasta dist, que são os arquivos que serão enviados.

Para subir o package para o Test PyPI precisaremos criar uma conta lá, clique aqui para fazer isso. Depois precisaremos baixar e atualizar o twine, um utilitário que simplifica o processo de envio: python -m pip install --user --upgrade twine.

Note: o twine ficará referenciado no PATH do sistema então precisaremos escrever todo o caminho até ele quando fomos usa-lo. Ele fica em c:\users\nome do usuário\appdata\local\programs\python\python36\Scripts.

Rode c:\users\nome do usuário\appdata\local\programs\python\python36\Scripts\twine upload --repository-url https://test.pypi.org/legacy/ dist/* para que o package seja subido para o PyPI, você precisará digitar o seu usuário e senha.

\o/ congrats \o/

Seu package está disponível para download, se você quiser baixa-lo para testar use python -m pip install --index-url https://test.pypi.org/simple/ projeto

Note que que o Test PyPI é para testes e por isso não é incomum que packages e contas sejam deletadas nele, se quer que seu projeto fique permanentemente online então precisará subir para o PyPI normal. Para isso você precisará registrar-se nele e omitir o --repository-url https://test.pypi.org/legacy/ no twine que fez anteriormente para subir o package e --index-url https://test.pypi.org/simple/ no comando pip anteriormente feito para baixar o package.

Aftermath & Exercícios

Parabéns por ter chegado até aqui! Qualquer dúvida é só perguntas nos comentários que tentarei responder.

Deixarei aqui os links para o projeto, no PyPI e GitHub. Você pode baixa-lo usando o comando pip install ventura

Agora deixarei alguns exercícios para você tentar em casa:
  • Diminuir os efeitos colaterais do projeto usando blocos try-except (diga: retorne falso no update_if_is_need se alguma função vital não está funcionando, como no caso de faltar internet)
  • O usuário pode estar versões atrás da atual, então crie um sistema que execute todas as atualizações na frente da sua.

Bem é isso, até a próxima. Talvez eu faça um vídeo com isso em funcionamento depois.


 
Herms, você é uma caixinha de surpresa que sempre me vem com algo sensacional quando apareço por aqui. Parabéns pela iniciativa e tópico, tá bem delicinha isso aqui s2

Particularmente, sempre achei muito gostosinho Python e queria ter aprendido ele ao invés de C quando tava estudando, mas acho que foi bom para eu desistir e fazer o que to fazendo hoje :kappa:

No mais, ótimo tópico ajudando como sempre, Heeeerms! :3
 
[member=1330]HermesPasser[/member]

Primeiramente,  ?f?o?r?a? ?T?e?m?e?r?  parabéns pelo belo tutorial, ficou bem legal e explicativo, espero ver outras aulas sua como essa!!

Eu mesmo nunca programei em Python, sei apenas alguns conceitos básicos da linguagem e que ela se parece muito com Ruby, na verdade uma boa parte da arquitetura do Ruby foi desenvolvida com base no Python, pois antes do Ruby, o Python já era uma das linguagens com menos burocracia para desenvolvimento, e isso permite um que os desenvolvedores criem programas de forma mais rápida e fácil e bem organizada (proposta que também foi o foco do Ruby e principalmente do framework Ruby on Rails que é mundialmente conhecido com a utilização no desenvolvimento WEB).

Por conta da sua facilidade, o Python é muito usado dentro do sistema operacional Linux, em algumas versões o Python já vem até instalado no sistema operacional por padrão.

A linguagem de programação Python é a preferida da NASA, NSA, Google e CIA por diversos motivos, uma das maiores rasões é a da "interpretação VS compilação", se um programador cria um programa que compila corretamente, não existe a garantia que isso irá quebrar todo o sistema que ele irá executar ou que irá corromper algumas coisas (intencionalmente ou não). Python é uma linguagem interpretada e com algumas heranças de segurança nesse respeito. Muitas empresas tem programas que precisam executar em diferentes sistemas operacionais e o Python permite isso, pois o mesmo script pode executar no Linux e no Windows sem precisar ser compilado.

Python também é utilizado em muitas outras coisas como:

Machine Learning (Aprendizado de máquina)
Data Science (Uma área interdisciplinar voltada para o estudo e a análise de dados)
Previsão de Preços (Amplamente utilizada em inventimentos)
Mineração de Bitcoin
Comunicação de Internet
Remote Adminstration Tools (RATs)
GUI (Interface gráfica)
Desenvolvimento de Jogos

Alguns anos atrás, comprei um livro muito bom, mas que ainda está na minha fila de leitura, esse livro ensina o desenvolvimento de jogos eletrônicos utilizando a engine PyGame.

capa-ampliada-9788575224526.jpg

Já que você está se aventurando nesse mundo do Python, eu ficaria muito feliz em ver um jogo seu mesmo que seja algo básico, que nos mostre como o Python é utilizado para criação de jogos.

Refente ao seu tutorial, achei muito interessante, gostaria de saber se você já está utilizando ele em algo real.

Também seria legal a apresentação de alguns conceitos iniciais sobre a linguagem, como o uso de indentação no lugar de chaves.

Gostaria também de ver uma aula sua sobre Programação Orientada a Objetos, pois seria algo que além de ajudar a comunidade entender, terá grande valor no seu projeto.
 
Primeiramente, OLHA O VÍDEO QUE SAIU! \O/  \O/  \O/

[youtube]https://www.youtube.com/watch?v=gHLClU0VyMA[/youtube]​

Resque comentou:
[member=1330]HermesPasser[/member]
Eu mesmo nunca programei em Python, sei apenas alguns conceitos básicos da linguagem e que ela se parece muito com Ruby, na verdade uma boa parte da arquitetura do Ruby foi desenvolvida com base no Python, pois antes do Ruby, o Python já era uma das linguagens com menos burocracia para desenvolvimento, e isso permite um que os desenvolvedores criem programas de forma mais rápida e fácil e bem organizada (proposta que também foi o foco do Ruby e principalmente do framework Ruby on Rails que é mundialmente conhecido com a utilização no desenvolvimento WEB).

Por conta da sua facilidade, o Python é muito usado dentro do sistema operacional Linux, em algumas versões o Python já vem até instalado no sistema operacional por padrão.

A linguagem de programação Python é a preferida da NASA, NSA, Google e CIA por diversos motivos, uma das maiores rasões é a da "interpretação VS compilação", se um programador cria um programa que compila corretamente, não existe a garantia que isso irá quebrar todo o sistema que ele irá executar ou que irá corromper algumas coisas (intencionalmente ou não). Python é uma linguagem interpretada e com algumas heranças de segurança nesse respeito. Muitas empresas tem programas que precisam executar em diferentes sistemas operacionais e o Python permite isso, pois o mesmo script pode executar no Linux e no Windows sem precisar ser compilado.

Python também é utilizado em muitas outras coisas como:

Machine Learning (Aprendizado de máquina)
Data Science (Uma área interdisciplinar voltada para o estudo e a análise de dados)
Previsão de Preços (Amplamente utilizada em inventimentos)
Mineração de Bitcoin
Comunicação de Internet
Remote Adminstration Tools (RATs)
GUI (Interface gráfica)
Desenvolvimento de Jogos

Estou ciente disso e fico feliz por você ter trazido isso a tona pois minha preguiça com certeza não deixaria eu fazer. hehehe

Resque comentou:
Alguns anos atrás, comprei um livro muito bom, mas que ainda está na minha fila de leitura, esse livro ensina o desenvolvimento de jogos eletrônicos utilizando a engine PyGame.

capa-ampliada-9788575224526.jpg
Conheço esse autor, tenho um livro (muito bom por sinal) da mesma editora aqui:

VisBildeServlet

Resque comentou:
Já que você está se aventurando nesse mundo do Python, eu ficaria muito feliz em ver um jogo seu mesmo que seja algo básico, que nos mostre como o Python é utilizado para criação de jogos.

Nunca mexi com isso no python apesar de já ter visto pessoas fazendo. Acho que seria algo grande de mais (mais de três partes) para um simples tutorial, aliás prefiro o gosu do ruby (polemico).

Resque comentou:
Refente ao seu tutorial, achei muito interessante, gostaria de saber se você já está utilizando ele em algo real.

Não pois não tenho nada em python rodando por aí, ele é uma evolução natural de algo semelhante que fiz em ruby tempos atrás.

Resque comentou:
Também seria legal a apresentação de alguns conceitos iniciais sobre a linguagem, como o uso de indentação no lugar de chaves.

Pensei em fazer isso, mas acho que alguém que tenha conhecimento da lógica conseguirá entender o code por analise (eu iria é acabar me perdendo em termos e faria um péssimo trabalho).

Resque comentou:
Gostaria também de ver uma aula sua sobre Programação Orientada a Objetos, pois seria algo que além de ajudar a comunidade entender, terá grande valor no seu projeto.

Se eu fizesse uma seria a mais enxuta possível pois eu iria é acabar me perdendo em termos e faria um péssimo trabalho². Mas quem sabe né? Tô com vontade de mexer com Perl e nunca mexi com OOB lá.

Desde já agradeço pelo feedback.
 
Voltar
Topo Inferior