Modèle pour l'écriture de scripts batch en python

Comme j'écris souvent des scripts en Python pour le travail, je publierai le code du modèle sous forme de mémorandum.

modèle de série python3

Aperçu

Ce modèle effectue les opérations suivantes:

Placement des fichiers

app_home/
       ├ bin/
       │   └  my_batch.py   #← Script à exécuter
       ├ conf/
       │   └  my_batch_conf.py #← Classe de réglage
       ├ lib/
       │   ├  __init__.py    #← Nécessaire pour charger le module
       │   └  my_lib.py      #← Bibliothèque
       ├ tests/        
       │   └  test_my_lib.py #← Code de test unitaire
       ├ log/                #← Destination de sortie du journal
       └ Pipfile             #← Lister les bibliothèques à utiliser

Contenu

Contenu du corps principal my_batch.py

import sys
import os
import click
import logging

#Le répertoire parent est le siège de l'application(${app_home})Mis à
app_home = os.path.abspath(os.path.join( os.path.dirname(os.path.abspath(__file__)) , ".." ))
# ${app_home}Vers le chemin de chargement de la bibliothèque
sys.path.append(os.path.join(app_home))

#Chargez votre propre bibliothèque
from lib.my_lib import MyLib

#Charger la classe de configuration
from conf.my_batch_conf import MyBatchConf

#Gestion des arguments de ligne de commande. must_arg est une option obligatoire, facultative_arg est facultatif
@click.command()
@click.option('--must_arg','-m',required=True)
@click.option('--optional_arg','-o',default="DefaultValue")
def cmd(must_arg,optional_arg):
    #Nom du programme sans extension de son propre nom(${prog_name})À
    prog_name = os.path.splitext(os.path.basename(__file__))[0]

    #Paramètres de l'enregistreur

    #format
    log_format = logging.Formatter("%(asctime)s [%(levelname)8s] %(message)s")
    #niveau
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    #Gestionnaire vers la sortie standard
    stdout_handler = logging.StreamHandler(sys.stdout)
    stdout_handler.setFormatter(log_format)
    logger.addHandler(stdout_handler)
    #Gestionnaire vers fichier journal
    file_handler = logging.FileHandler(os.path.join(app_home,"log", prog_name + ".log"), "a+")
    file_handler.setFormatter(log_format)
    logger.addHandler(file_handler)

    #Commencer le traitement
    try:
        #Sortie de journal
        logger.info("start")

        #Utilisation d'arguments de ligne de commande
        logger.error(f"must_arg = {must_arg}")
        logger.error(f"optional_arg = {optional_arg}")

        #Appel à la bibliothèque
        mylib = MyLib()
        logger.info(mylib.get_name())

        #Utilisation des valeurs de consigne
        logger.info(MyBatchConf.key1)
        logger.info(MyBatchConf.key2)

        #Même si une exception se produit ...
        raise Exception("My Exception")

    except Exception as e:
        #Attraper et enregistrer les exceptions
        logger.exception(e)
        sys.exit(1)

if __name__ == '__main__':
    cmd()        

Contenu de la classe de configuration conf / my_batch_conf.py

class MyBatchConf(object):
    key1 = "key1_value"
    key2 = True

*) J'avais l'habitude d'utiliser configParser avant, mais je n'ai pas besoin de l'analyser dans la classe de configuration, et je ne l'utilise pas maintenant car la complétion par IDE fonctionne.

Contenu de la bibliothèque my_lib.py

class MyLib(object):
    def get_name(self):
        return "my_lib"

Contenu du code de test unitaire de la bibliothèque test_my_lib.py

import sys,os
import unittest

# ../Mettez lib dans le chemin de chargement
app_home = os.path.abspath(os.path.join( os.path.dirname(os.path.abspath(__file__)) , ".." ))
sys.path.append(os.path.join(app_home,"lib"))

# ../Chargement de la bibliothèque en cours de test
from my_lib import MyLib

class TestMyLib(unittest.TestCase):

    def test_get_name(self):
        ml = MyLib()
        self.assertEqual("my_lib", ml.get_name())

if __name__ == '__main__':
    unittest.main()

Courir

Exécuter sans spécifier d'argument

$ python bin/my_batch.py

Résultat de l'exécution (le manuel apparaît par fonction clic)

Usage: my_batch.py [OPTIONS]
Try "my_batch.py --help" for help.

Error: Missing option "--must_arg" / "-m".

Exécuter avec des arguments

$ python bin/my_batch.py -m SpecifiedValue

Résultat d'exécution

2019-06-28 16:42:53,335 [    INFO] start
2019-06-28 16:42:53,335 [   ERROR] must_arg = SpecifiedValue
2019-06-28 16:42:53,335 [   ERROR] optional_arg = DefaultValue
2019-06-28 16:42:53,335 [    INFO] my_lib
2019-06-28 16:42:53,336 [    INFO] key1_value
2019-06-28 16:42:53,336 [    INFO] True
2019-06-28 16:42:53,336 [   ERROR] My Exception
Traceback (most recent call last):
  File "bin/my_batch.py", line 62, in cmd
    raise Exception("My Exception")
Exception: My Exception

Le même contenu est sorti dans le journal (log / my_batch.log)

2019-06-28 16:42:53,335 [    INFO] start
2019-06-28 16:42:53,335 [   ERROR] must_arg = SpecifiedValue
2019-06-28 16:42:53,335 [   ERROR] optional_arg = DefaultValue
2019-06-28 16:42:53,335 [    INFO] my_lib
2019-06-28 16:42:53,336 [    INFO] key1_value
2019-06-28 16:42:53,336 [    INFO] True
2019-06-28 16:42:53,336 [   ERROR] My Exception
Traceback (most recent call last):
  File "bin/my_batch.py", line 62, in cmd
    raise Exception("My Exception")
Exception: My Exception

tester

Exécuter un test unitaire

bash-3.2$ python tests/test_my_lib.py

Résultat d'exécution

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

tests Tout le code de test test_ * .py ci-dessous est exécuté en une

$ python -m unittest  discover tests "test_*.py"

finalement

Ce code est également disponible sur github → https://github.com/fetaro/python-batch-template-for-v3

modèle système python2

Aperçu

Ce modèle effectue les opérations suivantes:

Différence par rapport à la série python3

Placement des fichiers

app_home/
       ├ bin/
       │   └  my_batch.py   #← Script à exécuter
       ├ conf/
       │   └  my_batch.conf #← Fichier de configuration
       ├ lib/
       │   ├  __init__.py   #← Nécessaire pour charger le module
       │   └  my_lib.py     #← Bibliothèque
       ├ tests/        
       │   └  test_my_lib.py#← Code de test unitaire
       └ log/               #← Destination de sortie du journal

Contenu

Contenu de my_batch.py

# -*- coding: utf-8 -*-
import sys
import os
from optparse     import OptionParser
from ConfigParser import ConfigParser
import logging

#Le répertoire parent est le siège de l'application(${app_home})Mis à
app_home = os.path.abspath(os.path.join( os.path.dirname(os.path.abspath(__file__)) , ".." ))

# ${app_home}/Ajouter une bibliothèque au chemin de chargement de la bibliothèque
sys.path.append(os.path.join(app_home,"lib"))

#Chargez votre propre bibliothèque
from my_lib import MyLib

if __name__ == "__main__" :
    #Nom du programme sans extension de son propre nom(${prog_name})À
    prog_name = os.path.splitext(os.path.basename(__file__))[0]

    #Perspective facultative
    usage = "usage: %prog (Argument-1) [options]"
    parser = OptionParser(usage=usage)
    parser.add_option("-d", "--debug",dest="debug", action="store_true", help="debug", default=False)

    #Stocker les options et les arguments séparément
    (options, args) = parser.parse_args()

    #Vérification des arguments
    if len(args) != 1:
        sys.stderr.write("argument error. use -h or --help option\n")
        sys.exit(1)

    #Lire le fichier de configuration
    config = ConfigParser()
    conf_path = os.path.join(app_home,"conf", prog_name + ".conf")
    config.read(conf_path)

    #Paramètres de l'enregistreur

    #format
    log_format = logging.Formatter("%(asctime)s [%(levelname)8s] %(message)s") 
    #niveau
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    #Gestionnaire vers la sortie standard
    stdout_handler = logging.StreamHandler(sys.stdout)
    stdout_handler.setFormatter(log_format)
    logger.addHandler(stdout_handler)
    #Gestionnaire vers fichier journal
    file_handler = logging.FileHandler(os.path.join(app_home,"log", prog_name + ".log"), "a+")
    file_handler.setFormatter(log_format)
    logger.addHandler(file_handler)

    
    #Commencer le traitement
    try:
        #Sortie de journal
        logger.info("start")
        logger.error("arg1 = {0}".format(args[0]))

        #Obtenez des options
        logger.info(options.debug)

        #Appel à la bibliothèque
        mylib = MyLib()
        logger.info(mylib.get_name())

        #Lire la valeur de réglage
        logger.info(config.get("section1","key1"))
        logger.info(config.getboolean("section2","key2"))

        #Même si une exception se produit ...
        raise Exception("My Exception")
        
    except Exception as e:
        #Attraper et enregistrer les exceptions
        logger.exception(e)
        sys.exit(1)
        

Contenu de my_batch.conf

[section1]
key1  = key1_value

[section2]
key2 = true

Contenu de my_lib.py

class MyLib(object):
    def get_name(self):
        return "my_lib"

Contenu du code de test unitaire test_my_lib.py

# -*- coding: utf-8 -*-
import sys,os
import unittest

# ../Mettez lib dans le chemin de chargement
app_home = os.path.abspath(os.path.join( os.path.dirname(os.path.abspath(__file__)) , ".." ))
sys.path.append(os.path.join(app_home,"lib"))

# ../Chargement de la bibliothèque en cours de test
from my_lib import MyLib

class TestMyLib(unittest.TestCase):

    def test_get_name(self):
        ml = MyLib()
        self.assertEqual("my_lib", ml.get_name())

if __name__ == '__main__':
    unittest.main()

Courir

bash-3.2$ python bin/my_batch.py argument1
2016-08-16 23:25:03,492 [    INFO] start
2016-08-16 23:25:03,492 [   ERROR] arg1 = argument1
2016-08-16 23:25:03,492 [    INFO] False
2016-08-16 23:25:03,492 [    INFO] my_lib
2016-08-16 23:25:03,492 [    INFO] key1_value
2016-08-16 23:25:03,492 [    INFO] True
2016-08-16 23:25:03,492 [   ERROR] My Exception
Traceback (most recent call last):
  File "bin/my_batch.py", line 73, in <module>
    raise Exception("My Exception")
Exception: My Exception

Contenu du journal (log / my_batch.log)

2016-08-16 23:25:03,492 [    INFO] start
2016-08-16 23:25:03,492 [   ERROR] arg1 = argument1
2016-08-16 23:25:03,492 [    INFO] False
2016-08-16 23:25:03,492 [    INFO] my_lib
2016-08-16 23:25:03,492 [    INFO] key1_value
2016-08-16 23:25:03,492 [    INFO] True
2016-08-16 23:25:03,492 [   ERROR] My Exception
Traceback (most recent call last):
  File "bin/my_batch.py", line 73, in <module>
    raise Exception("My Exception")
Exception: My Exception

Résultat de l'exécution du test unitaire

bash-3.2$ python tests/test_my_lib.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

tests Lors du test de tout le code de test test_ *. Py sous ce qui suit à la fois

bash-3.2$ python -m unittest  discover tests "test_*.py"

Le contenu de ce fichier est également publié sur github. Faites ce que vous voulez → https://github.com/fetaro/python-batch-template

Recommended Posts

Modèle pour l'écriture de scripts batch en python
Techniques de tri en Python
Modèle Python pour Codeforces-test manuel-
Mise en retrait des scripts python
À propos de "for _ in range ():" de python
Rechercher des commandes externes avec python
Notes de grammaire minimales pour écrire Python
Modèle de prétraitement pour l'analyse des données (Python)
Exécutez unittest en Python (pour les débutants)
Lire et écrire du texte en Python
Lors de l'écriture d'un programme en Python
Note de nfc.ContactlessFrontend () de nfcpy de python
Inject est recommandé pour DDD en Python
Conseils pour gérer les binaires en Python
Résumé de diverses instructions for en Python
Tapez les annotations pour Python2 dans les fichiers stub!
Script de pilote pour le calcul paramétrique des scripts Python
Je ne peux pas déboguer les scripts python dans Eclipse
Traiter plusieurs listes avec for en Python
MongoDB avec Python pour la première fois
Obtenez un jeton pour conoha avec python
Exemple de gestion des fichiers eml en Python
Fiche de triche AtCoder en python (pour moi-même)
J'ai cherché un nombre premier avec python
Remarques sur l'utilisation de python (pydev) avec eclipse
Conseils pour créer de petits outils avec python
Utilisez pathlib dans Maya (Python2.7) en préparation du prochain Python3.7
30/10/2016 else pour Python3> pour:
[Astuces] Écriture facile à lire lors de la connexion de fonctions en Python
Quadtree en Python --2
python [pour moi]
CURL en Python
CERTIFICATE_VERIFY_FAILED dans Python 3.6, le programme d'installation officiel de macOS
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Modèle Python qui effectue une analyse des journaux à une vitesse explosive
Python Pandas ne convient pas au traitement par lots
Méta-analyse en Python
Unittest en Python
Créer un environnement pour exécuter des scripts Python (pour Mac)
Apprenez le modèle de conception "Méthode de modèle" en Python
Discord en Python
Ajouter un devis ">" pour répondre aux e-mails en Python3
DCI en Python
tri rapide en python
nCr en python
Paramètres de journalisation pour la rotation quotidienne des journaux avec python
Lire et écrire des fichiers CSV et JSON avec Python
Écriture de base Python
Conseils pour accéder à l'API ATND avec Python
Afficher la bougie de données FX (forex) en Python
N-Gram en Python
Programmation avec Python
Tutoriel Boost.NumPy pour l'extension de Python en C ++ (pratique)
Remplissez les valeurs des variables dynamiques avec 0 en Python