Utilitários do Python

Nesta seção, analisaremos alguns dos diversos módulos utilitários padrão de Python para resolver problemas comuns.

Sistema de arquivos – os, os.path, Shutil

Os módulos *os* e *os.path* incluem muitas funções para interagir com o sistema de arquivos. O módulo *shutil* pode copiar arquivos.

  • documentos do módulo do SO
  • usernames = os.listdir(dir) -- lista de nomes de arquivos no caminho de diretório (sem incluir . e ..). Os nomes de arquivo são apenas os nomes no diretório, não seus caminhos absolutos.
  • os.path.join(dir, username) -- dado o nome de arquivo da lista acima, use-o para unir o diretório e o nome de arquivo e criar um caminho
  • os.path.abspath(path) -- específico para um caminho, retorna uma forma absoluta, por exemplo, /home/nick/foo/bar.html
  • os.path.dirname(path), os.path.basename(path): em dir/foo/bar.html, retorna o nome de dir/foo "dir/foo" e o nome de base "bar.html"
  • os.path.exists(path) -- verdadeiro se existir
  • os.mkdir(dir_path) -- cria um diretório, os.makedirs(dir_path) cria todos os diretórios necessários nesse caminho
  • Shutil.copy(source-path, dest-path) -- copiar um arquivo (deve haver diretórios de caminho de destino)
## Example pulls filenames from a dir, prints their relative and absolute paths
def printdir(dir):
  filenames = os.listdir(dir)
  for filename in filenames:
    print(filename)  ## foo.txt
    print(os.path.join(dir, filename)) ## dir/foo.txt (relative to current dir)
    print(os.path.abspath(os.path.join(dir, filename))) ## /home/nick/dir/foo.txt

A exploração de um módulo funciona bem com as funções integradas do python help() e dir(). No intérprete, faça um "import os" e use estes comandos para ver o que está disponível no módulo: dir(os), help(os.listdir), dir(os.path), help(os.path.dirname).

Como executar processos externos -- subprocesso

O módulo *subprocess* é uma maneira simples de executar um comando externo e capturar a saída dele.

  • documentos do módulo subprocess
  • output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) -- executa o comando, espera que ele saia e retorna o texto de saída. O comando é executado com a saída e o erro padrão combinados em um texto de saída. Se falhar, ele gera um CalledProcessError.
  • Para ter mais controle sobre a execução do subprocesso, consulte a classe subprocess.popen (link em inglês).
  • Existe também um subprocess.call(cmd) simples que executa o comando, despeja a saída na saída e retorna o código do erro. Isso funciona se você quiser executar o comando, mas não precisar capturar a saída nas estruturas de dados do Python.
import subprocess

## Given a dir path, run an external 'ls -l' on it --
## shows how to call an external program
def listdir(dir):
  cmd = 'ls -l ' + dir
  print("Command to run:", cmd)   ## good to debug cmd before actually running it
  (status, output) = subprocess.getstatusoutput(cmd)
  if status:    ## Error case, print the command's output to stderr and exit
    sys.stderr.write(output)
    sys.exit(status)
  print(output)  ## Otherwise do something with the command's output

Exceções

Uma exceção representa um erro de tempo de execução que interrompe a execução normal em uma determinada linha e transfere o controle para o código de tratamento de erros. Esta seção apresenta os usos mais básicos das exceções. Por exemplo, um erro de tempo de execução pode ser que uma variável usada no programa não tenha um valor (ValueError .. você provavelmente já viu isso algumas vezes) ou um erro de operação de abertura de arquivo porque um arquivo não existe (IOError). Saiba mais no tutorial de exceções e veja a lista completa de exceções.

Sem nenhum código de tratamento de erros (como fizemos até agora), uma exceção de tempo de execução apenas interrompe o programa com uma mensagem de erro. Esse é um bom comportamento padrão, e você já o viu várias vezes. É possível adicionar uma estrutura "tentar/exceto" ao código para lidar com exceções, como esta:

  try:
    ## Either of these two lines could throw an IOError, say
    ## if the file does not exist or the read() encounters a low level error.
    f = open(filename, 'rb')
    data = f.read()
    f.close()
  except IOError:
    ## Control jumps directly to here if any of the above lines throws IOError.
    sys.stderr.write('problem reading:' + filename)
  ## In any case, the code then continues with the line after the try/except

A seção try: inclui o código que pode gerar uma exceção. A seção "exceto:" contém o código a ser executado se houver uma exceção. Se não houver exceção, a seção "exception:" será ignorada (ou seja, esse código serve apenas para tratamento de erros e não para o caso "normal" do código). Você pode mostrar um ponteiro para o próprio objeto de exceção com a sintaxe "exceto IOError as e: .." (e aponta para o objeto da exceção).

HTTP -- urllib e urlparse

O módulo *urllib.request* fornece busca de URL, tornando um URL parecido com um arquivo que você pode ler. O módulo *urlparse* pode separar e reunir URLs.

  • Documentos do módulo urllib.request
  • ufile = urllib.request.urlopen(url) -- retorna um arquivo como objeto para esse URL
  • text = ufile.read() -- pode ler a partir dele, como um arquivo (readlines() etc. também funcionam)
  • info = ufile.info() -- as metainformações dessa solicitação. info.gettype() é o tipo MIME, por exemplo, "text/html"
  • baseurl = ufile.geturl() -- obtém o URL "base" para a solicitação, que pode ser diferente do original por causa de redirecionamentos
  • urllib.request.urlretrieve(url, username) - faz o download dos dados do URL para o caminho de arquivo especificado
  • urllib.parse.urljoin(baseurl, url) – considerando um URL que pode ou não estar completo e o baseurl da página de onde vem, um URL completo é retornado. Use geturl() acima para fornecer o URL de base.

Todas as exceções estão em urllib.error.

from urllib.request import urlopen

## Given a url, try to retrieve it. If it's text/html,
## print its base url and its text.
def wget(url):
  ufile = urlopen(url)  ## get file-like object for url
  info = ufile.info()   ## meta-info about the url content
  if info.get_content_type() == 'text/html':
    print('base url:' + ufile.geturl())
    text = ufile.read()  ## read all its text
    print(text)

O código acima funciona bem, mas não incluirá tratamento de erros se um URL não funcionar por algum motivo. Esta é uma versão da função que adiciona a lógica try/exception para mostrar uma mensagem de erro se a operação do URL falhar.

Se urlopen() parecer estar suspenso, seu sistema pode não permitir o acesso direto a alguns endereços http. Para verificar isso, tente buscar o mesmo URL usando wget ou curl. Se esses programas também falharem, você precisará buscar conteúdo HTTP com um serviço de proxy. A configuração do acesso por proxy não é abordada por este tutorial.

## Version that uses try/except to print an error message if the
## urlopen() fails.
def wget2(url):
  try:
    ufile = urlopen(url)
    if ufile.info().get_content_type() == 'text/html':
      print(ufile.read())
  except IOError:
    print('problem reading url:', url)

Exercício

Para praticar o sistema de arquivos e o material de comandos externos, consulte o Exercício de cópia especial. Para praticar o material urllib, consulte o Exercício de quebra-cabeças de registro.