[PYTHON] Les informations minimales sur le ciment dont vous avez besoin

What's Cement

Framework d'application en ligne de commande python. ciment. Je n'ai pas beaucoup d'informations sur le japonais, alors faites une note pour moi-même sur Google plus tard.

Il dit "Un cadre, pour le CLI Ninja." Est-ce que toutes les choses cool sont ninja?

Installation

Vous pouvez l'installer avec pip.

pip install cement

Développement d'applications en ligne de commande

Application simple

Quelque chose comme ça. Si vous souhaitez créer un outil à fonction unique, ce niveau de modèle suffit.

myapp1 -h
myapp1 --option <option>
myapp1 --option -F <argument>
myapp1 --option -F <argument> <省略可能なargument>
myapp1 --option -F <argument> <省略可能なargument> <省略可能なargument> .... 

Un contrôleur. Les options à définir individuellement sont «-F» et «--option». Un autre argument requis. Un nombre arbitraire d'arguments.

myapp.py


#-*- coding:utf-8 -*-
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
from cement.core import handler

class BaseController(CementBaseController):
    class Meta:
        label = 'base'
        description = "Ceci est l'explication de cette commande"
        arguments = [
            ( ['-o', '--option'],
              dict(action='store', default="default option value",help='Je vais spécifier l'option') ),
            ( ['-F'],
              dict(action='store_true', help='Option F supérieure') ),
            (['param1'], dict(action='store', nargs=1, help = "C'est le premier argument")),
            (['param2'], dict(action='store', nargs="*", metavar="PARAM2", help = "C'est le deuxième argument", default = ["default ext value"])),
            ]

    @expose(hide=True)
    def default(self):
        self.app.log.debug("Traitement par défaut-début")
        if self.app.pargs.option:
            print "Les paramètres spécifiés par option sont<%s>" % self.app.pargs.option

        if self.app.pargs.F:
            print "L'option F a été spécifiée"

        if self.app.pargs.param1:
            print "argument: %s" % self.app.pargs.param1[0]

        if self.app.pargs.param2:
            print "argument: %s" % self.app.pargs.param2[0]

        self.app.log.info("Traitement par défaut")
        self.app.log.debug("Traitement par défaut-Fin")

class App(CementApp):
    class Meta:
        label = 'app'
        base_controller = 'base'
        handlers = [BaseController]

with App() as app:
    app.run()

Sous-commande

Le contrôleur interprète la méthode avec @exporse () comme une sous-commande. La méthode default est appelée lorsque la sous-commande est omise.

    @expose(aliases=["y!", "sb"], help="Description de la méthode par défaut")
    def yahoo(self):
        self.app.log.info("traitement Yahoo")
        
    @expose(hide=True)
    def default(self):
        self.app.log.info("C'est le processus par défaut")

Les sous-commandes et les arguments de position sont difficiles à utiliser. Cela est dû au fait que les arguments et les paramètres d'option sont contrôlés par contrôleur, et si une sous-commande entre en collision avec un argument, elle sera interprétée comme une sous-commande. Par exemple, dans l'exemple ci-dessus, si vous omettez la sous-commande et passez default ou yahoo comme premier argument, cela ne fonctionnera pas. Elle sera interprétée comme une sous-commande.

Ceci est inévitable car il est inévitable lors de la conception d'une sous-commande de type CLI.

À propos, la définition de l'argument est commune dans le même contrôleur. Par conséquent, s'il existe un contrôleur qui a un argument requis, une sous-commande qui n'a pas d'argument ne peut pas y être définie.

Si vous voulez faire une telle conception, utilisez Namespace (contrôleur imbriqué) décrit plus loin.

Espace de nom

Vous pouvez imbriquer les contrôleurs en tant qu'espace de noms. Example --Multiple Stacked Controllers est facile à comprendre.

Créez le système de commande suivant.

myapp2.py <argument>
myapp2.py sub
myapp2.py sub hello
myapp2.py sub world

Notez que l'appel simple à myapp2.py (c'est-à-dire MainController) nécessite le premier argument, mais pas l'espace de noms sub. «Hello» et «world» sont des sous-commandes de l'espace de noms «sub», pas des arguments.

myapp2.py


#-*- coding:utf-8 -*-
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
from cement.core import handler

class BaseController(CementBaseController):
    class Meta:
        label = 'base'
        description = "C'est une explication de la commande de base."


class MainController(CementBaseController):
    class Meta:
        label = 'main'
        description = "C'est une description du contrôleur principal"
        stacked_on = 'base'
        stacked_type = 'embedded'
        arguments = [
            (['param1'], dict(action='store', nargs=1, help="Premier argument requis"))
            ]

    @expose(hide=True)
    def default(self):
        self.app.log.debug("Traitement par défaut-début")
        print "argument: %s" % self.app.pargs.param1[0]
        self.app.log.info("Traitement par défaut")
        self.app.log.debug("Traitement par défaut-Fin")

class SubController(CementBaseController):
    class Meta:
        label = 'sub'
        description = "C'est une description du sous-contrôleur"
        stacked_on = 'base'
        stacked_type = 'nested'

        arguments = [ ]

    @expose(hide=True)
    def default(self):
        self.app.log.info("Traitement du sous-contrôleur")

    @expose()
    def hello(self):
        self.app.log.info("hello world")

    @expose()
    def world(self):
        self.app.log.info("the world")

class App(CementApp):
    class Meta:
        label = 'app'
        base_controller = 'base'
        handlers = [BaseController, MainController, SubController]

with App() as app:
    app.run()

Eh bien, cependant, du point de vue de l'utilisateur de la commande, sub est une sous-commande.

Renvoie n'importe quel code d'état

Vous pouvez attribuer une valeur à app.exit_code.

    @expose(hide=True)
    def default(self):
        self.app.log.error('Pas encore implémenté')
        self.app.exit_code = 1

Sachez que la valeur de retour d'une sous-commande peut devenir par inadvertance la valeur de retour de la commande entière.

Recevoir une entrée sur un tuyau

Faites-le fonctionner avec les spécifications de tuyau et de fichier.

cement3.py hello.txt
cat hello.txt | cement3.py

Vous pouvez écrire intelligemment en combinant ʻargparse.FileTypeetdefault = sys.stdin`. Peut être un argument optionnel avec nargs = "?".

cement3.py


#-*- coding:utf-8 -*-
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
from cement.core import handler
import argparse
import sys

class BaseController(CementBaseController):
    class Meta:
        label = 'base'
        description = "Ceci est l'explication de cette commande"
        arguments = [
            (["input"], dict(nargs='?', type=argparse.FileType('r'), default=sys.stdin ))
            ]

    @expose(hide=True)
    def default(self):
        self.app.log.debug("Traitement par défaut-début")
        for line in self.app.pargs.input:
          print ">>> %s" % line
        self.app.log.debug("Traitement par défaut-Fin")

class App(CementApp):
    class Meta:
        label = 'app'
        base_controller = 'base'
        handlers = [BaseController]

with App() as app:
    app.run()

Résumé

--Cement Le design est plutôt cool, alors utilisons-le et créons une CLI sympa.

Recommended Posts

Les informations minimales sur le ciment dont vous avez besoin
Vous aurez peut-être besoin de git pour installer l'extension jupyter lab
Comment collectez-vous les informations?
Pouvez-vous supprimer ce fichier?
[Version simplifiée] Comment exporter les informations d'enregistrement du compteur de lecture minimum