What's Cement
Python-Befehlszeilenanwendungsframework. Zement. Ich habe nicht viele japanische Informationen, machen Sie sich also eine Notiz für mich, um später zu googeln.
Es heißt "Ein Framework für die CLI Ninja". Sind all die coolen Dinge Ninja?
Sie können es mit pip installieren.
pip install cement
Etwas wie das. Wenn Sie ein Tool mit nur einer Funktion erstellen möchten, reicht diese Vorlagenebene aus.
myapp1 -h
myapp1 --option <Möglichkeit>
myapp1 --option -F <Streit>
myapp1 --option -F <Streit> <省略可能なStreit>
myapp1 --option -F <Streit> <省略可能なStreit> <省略可能なStreit> ....
Ein Controller. Die einzeln zu definierenden Optionen sind "-F" und "--option". Ein weiteres erforderliches Argument. Eine beliebige Anzahl von Argumenten.
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 = "Dies ist die Erklärung dieses Befehls"
arguments = [
( ['-o', '--option'],
dict(action='store', default="default option value",help='Ich werde die Option angeben') ),
( ['-F'],
dict(action='store_true', help='Obere F-Option') ),
(['param1'], dict(action='store', nargs=1, help = "Es ist das erste Argument")),
(['param2'], dict(action='store', nargs="*", metavar="PARAM2", help = "Es ist das zweite Argument", default = ["default ext value"])),
]
@expose(hide=True)
def default(self):
self.app.log.debug("Standardverarbeitung-Start")
if self.app.pargs.option:
print "Die durch die Option angegebenen Parameter sind<%s>" % self.app.pargs.option
if self.app.pargs.F:
print "Die Option F wurde angegeben"
if self.app.pargs.param1:
print "Streit: %s" % self.app.pargs.param1[0]
if self.app.pargs.param2:
print "Streit: %s" % self.app.pargs.param2[0]
self.app.log.info("Standardverarbeitung")
self.app.log.debug("Standardverarbeitung-Ende")
class App(CementApp):
class Meta:
label = 'app'
base_controller = 'base'
handlers = [BaseController]
with App() as app:
app.run()
Der Controller interpretiert die Methode mit "@exporse ()" als Unterbefehl. Die Standardmethode wird aufgerufen, wenn der Unterbefehl weggelassen wird.
@expose(aliases=["y!", "sb"], help="Beschreibung der Standardmethode")
def yahoo(self):
self.app.log.info("Yahoo Verarbeitung")
@expose(hide=True)
def default(self):
self.app.log.info("Dies ist der Standardprozess")
Unterbefehle und Positionsargumente sind schwer zu verwenden. Dies liegt daran, dass die Argumente und Optionseinstellungen Controller für Controller sind. Wenn ein Unterbefehl mit einem Argument kollidiert, wird er als Unterbefehl interpretiert. Wenn Sie im obigen Beispiel beispielsweise den Unterbefehl weglassen und "default" oder "yahoo" als erstes Argument übergeben, funktioniert dies nicht. Es wird als Unterbefehl interpretiert.
Dies ist unvermeidlich, da dies beim Entwerfen einer CLI vom Unterbefehlstyp unvermeidlich ist.
Übrigens ist die Definition des Arguments im selben Controller üblich. Wenn es einen Controller mit einem erforderlichen Argument gibt, kann daher kein Unterbefehl ohne Argument definiert werden.
Wenn Sie ein solches Design erstellen möchten, verwenden Sie den später beschriebenen Namespace (verschachtelter Controller).
Sie können Controller als Namespace verschachteln. Beispiel - Mehrere gestapelte Controller ist leicht zu verstehen.
Erstellen Sie das folgende Befehlssystem.
myapp2.py <Streit>
myapp2.py sub
myapp2.py sub hello
myapp2.py sub world
Beachten Sie, dass für den einfachen Aufruf von myapp2.py (dh "MainController") das erste Argument erforderlich ist, für den Namespace "sub" jedoch nicht. Sowohl "Hallo" als auch "Welt" sind Unterbefehle des Namespace "Unter", keine Argumente.
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 = "Es ist eine Erklärung des Basisbefehls."
class MainController(CementBaseController):
class Meta:
label = 'main'
description = "Es ist eine Beschreibung des Hauptcontrollers"
stacked_on = 'base'
stacked_type = 'embedded'
arguments = [
(['param1'], dict(action='store', nargs=1, help="Erforderliches erstes Argument"))
]
@expose(hide=True)
def default(self):
self.app.log.debug("Standardverarbeitung-Start")
print "Streit: %s" % self.app.pargs.param1[0]
self.app.log.info("Standardverarbeitung")
self.app.log.debug("Standardverarbeitung-Ende")
class SubController(CementBaseController):
class Meta:
label = 'sub'
description = "Es ist eine Beschreibung des Subcontrollers"
stacked_on = 'base'
stacked_type = 'nested'
arguments = [ ]
@expose(hide=True)
def default(self):
self.app.log.info("Subcontroller-Verarbeitung")
@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()
Nun, aus Sicht des Befehlsbenutzers ist sub
jedoch ein Unterbefehl.
Sie können app.exit_code einen Wert zuweisen.
@expose(hide=True)
def default(self):
self.app.log.error('Noch nicht implementiert')
self.app.exit_code = 1
Beachten Sie, dass der Rückgabewert eines Unterbefehls möglicherweise versehentlich zum Rückgabewert des gesamten Befehls wird.
Stellen Sie sicher, dass es sowohl mit der Pipe- als auch mit der Dateispezifikation funktioniert.
cement3.py hello.txt
cat hello.txt | cement3.py
Sie können intelligent schreiben, indem Sie "argparse.FileType" und "default = sys.stdin" kombinieren. Kann ein optionales Argument mit nargs = "?" Sein.
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 = "Dies ist die Erklärung dieses Befehls"
arguments = [
(["input"], dict(nargs='?', type=argparse.FileType('r'), default=sys.stdin ))
]
@expose(hide=True)
def default(self):
self.app.log.debug("Standardverarbeitung-Start")
for line in self.app.pargs.input:
print ">>> %s" % line
self.app.log.debug("Standardverarbeitung-Ende")
class App(CementApp):
class Meta:
label = 'app'
base_controller = 'base'
handlers = [BaseController]
with App() as app:
app.run()
--Cement Das Design ist ziemlich cool, also verwenden wir es und erstellen eine coole CLI.
Recommended Posts