pythonista: molde inicial

una base para cualquier script:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# Copyright 2017
#
# This file is part of xxxxxx.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##################
#
# uso y funcionalidad
#
##################
#
# to-do:
#
##################

import sys
import logging, argparse
from subprocess import Popen, PIPE

# variables globales
VERSION=0.1
TEMPDIR='tmp'
INPUTFILE='lista.txt'
LOGDEST = "/var/log/salida.log"


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--debug',
                        help='show debug messages',
                        action='store_true')
    parser.add_argument('-v', '--version',
                        help='show version info',
                        action='version',
                        version=VERSION)
    parser.add_argument('-i','--inputfile',
                        action='store',
                        help = 'input file')
    parser.add_argument('-l','--logdest',
                        action='store',
                        help = 'log file destination')
    parser.add_argument('-t','--tempdir',
                        action='store',
                        help = 'temp dir')
    args = parser.parse_args()

    if args.debug:
    # logging to file
        logging.basicConfig(filename=LOGDEST,format='%(asctime)s %(levelname)s:%(message)s',level=logging.DEBUG)
    # logging to stdout
    #    logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.DEBUG)
    else:
    # logging to file
        logging.basicConfig(filename=LOGDEST,format='%(asctime)s %(levelname)s:%(message)s',level=logging.INFO)
    # logging to stdout
    #    logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.INFO)


    if args.inputfile:
        global INPUTFILE
        INPUTFILE = args.inputfile
    if args.logdest:
        global LOGDEST
        LOGDEST = args.logdest
    if args.tempdir:
        global TEMPDIR
        TEMPDIR = args.tempdir

        (...new code here...)

if __name__ == "__main__":
    main()

 

Pythonista, licensing

 

#
#
# Copyright 2016 xxx xxxx
#
# This file is part of xxxxxx.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##################

Pythonista, argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--debug',
                        help='show debug messages',
                        action='store_true')
    parser.add_argument('-v', '--version',
                        help='show version info',
                        action='version',
                        version=VERSION)
    parser.add_argument('-s','--serial',
                        action='store',
                        help = 'serial port')
    parser.add_argument('-p','--port',
                        action='store',
                        help = 'carbon server port')
    parser.add_argument('-c','--carbon',
                        action='store',
                        help = 'carbon server')
    args = parser.parse_args()

    if args.debug:
        logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.DEBUG)
    else:
        logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.ERROR)

    if args.serial:
        global SERIAL_PORT
        SERIAL_PORT = args.serial
    if args.port:
        global CARBON_PORT
        CARBON_PORT = args.port
    if args.carbon:
        global CARBON_SERVER
        CARBON_SERVER = args.carbon

mas en el tutorial oficial

pythonista, checklist

checklist a incorporar en todo script python, para avanzar en un proceso de modernizacion (!)

# to-do: 
# - licensing (aqui)
# - from print to logger (aqui)
# - 4 indentation (aqui)
# - de commands.getoutput a Popen (aqui)
# - unspaghetti (parentesis y salto de linea)
# - utf8 (aqui)
# - argparse, ayuda y argumentos (aqui)
# - string interpolation, not concatenation (aqui)
# - no import *
# - review variable names _, english
# - de string.find a in (aqui)
# - review unspanish
# - +=
# - function docstrings
# - try: except: in imports

Pythonista, logging y loglevels

el 99% de los PRINTs de los scripts son mensajes de log, en diferentes LOGLEVELS.

Para una primera iteracion solo usamos salida estandar por terminal (no fiechero)

  • en cada caso diferenciar el loglevel al que pertenecen
  • inicializar el logging:
logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', level=logging.DEBUG)
  • sustituir todos los print por logging

 

Pythonista, de commands.getoutput a Popen

hace 8 años que se deprecó commands, y el japones seguia alerta en su isla desierta, sin saber que la guerra ya habia terminado.

pasos:

  • partimos de un comando en un string
  • el resultado es la salida, como string, para ser procesado por quien siga
  • pasar el string del comando por shlex.split:
    args = shlex.split(comando)
    proceso = Popen(args, stdout=PIPE, stderr=PIPE, shell=False)
    salida, error = proceso.communicate()
    if proceso.returncode !=0:
        print("mal")

    Despues hay que atender al contenido de proceso.returncode, si es distinto de cero, algo ha ido mal

  • para dos comandos unidos por pipe:
mensaje = "sensor.medida.temp {} {}".format( t, int(time()))
logging.debug(mensaje)
comando1 = ['echo ',  mensaje ]
comando2 = [ 'nc', '-q0', CARBON_SERVER, CARBON_PORT]
proc1 = Popen(comando1, stdout=PIPE, shell=False)
proc2 = Popen(comando2, stdin=proc1.stdout, stdout=PIPE, shell=False)
logging.debug(proc2.communicate()[0]
  • habiendo importado lo necesario:
from subprocess import Popen, PIPE