Dynamische Befehlsausführung, Parsen und Speicher.
Mit Dyncommands können Sie Python -Funktionen dynamisch importieren und ausführen. Nützlich zum Hinzufügen von Befehlen zu IRC -Chatbots oder CLI -Anwendungen ohne Neustart.
Bei der Parsen einer Zeichenfolge trennt er den Befehlsnamen von Argumenten und führt die gespeicherte Funktion mit diesen Argumenten aus. Jedes Mal, wenn der Parser aufgerufen wird, können Sie in Ihren eigenen benutzerdefinierten KWARGs übergeben, auf die der Befehl zugreifen wird.
Alle Befehlsmodule werden durch eingesperrtes Python zusammengestellt, bevor sie ausgeführt werden dürfen. Sie können die eingeschränkte Ausführung deaktivieren, indem Sie CommandParser._unrestricted zu True einstellen, obwohl dies bei der Ausführung nicht vertrauenswürdiger Code stark entmutigt ist.
from pathlib import Path
from dyncommands import CommandParser , CommandContext , CommandSource
output : str = ''
def callback ( text , * args ):
global output
output = text
path = Path ( 'path/to/directory' ) # Must be a directory with a `commands.json` file in it
parser = CommandParser ( path ) # Create the parser, which initializes using data located in the path directory
source = CommandSource ( callback ) # Create a source, which is used to talk back to the caller
input_ = 'command-that-returns-wow arg1 arg2' # this command would call zzz__command-that-returns-wow.py with arg1 and arg2
parser . parse ( CommandContext ( input_ , source )) # Parse the new context and run the command and callback (If no errors occur)
assert output == 'wow' Metadaten für Befehle werden in der commands.json -Datei des Verzeichnisses CommandParser.commands_path gespeichert. Hier werden alle Daten für den Parser geladen und gespeichert.
Alle commands.json -Dateien werden mit JSON -Schemas über das Json -Schema Python -Paket validiert
| Schlüssel | Typ | Beschreibung | Standard | erforderlich |
|---|---|---|---|---|
commandPrefix | Saite | Saiten müssen mit diesem Präfix beginnen, sonst wird es ignoriert. Die leere Zeichenfolge akzeptiert alle. | N / A | Ja |
commands | Array [ Befehl ] | Enthält Metadaten für die gespeicherten Befehlsmodule. | N / A | Ja |
| Schlüssel | Typ | Beschreibung | Standard | erforderlich |
|---|---|---|---|---|
name | Saite | Identifiziert den Befehl den Befehlsparser eindeutig. | N / A | Ja |
usage | Saite | Nutzungsinformationen (wie man Argumente verwendet). | "" " | NEIN |
description | Saite | Beschreibung des Befehls. | "" " | NEIN |
permission | ganze Zahl | Die Berechtigungsstufe, die die Befehlsource benötigt, um den Befehl auszuführen. | 0 | NEIN |
function | Boolean , Null | Ob es ein zugeordnetes Python -Modul zum Laden gibt. | NULL | NEIN |
children | Array [ Befehl ] | Unterkommandiere; Diese werden durch die Funktion des Elternteils behandelt. (Keine zugehörigen Module für sich selbst). | [] | NEIN |
overridable | boolean | Ob der CommandParser alle Daten in diesem Objekt überschreiben kann (muss manuell aktiviert sein). | WAHR | NEIN |
disabled | boolean | Wenn True noch laden, aber einen Behinderungseur erhöhen, wenn Sie versuchen, auszuführen. | FALSCH | NEIN |
HINWEIS: Befehlsmodule werden nicht geladen, es sei denn, sie sind in commands.json mit dem function auf true aufgeführt.
commands.json Inhalt: {
"commandPrefix" : " ! " ,
"commands" : [
{
"name" : " test " ,
"usage" : " test [*args:any] " ,
"description" : " Test command. " ,
"permission" : 500 ,
"function" : true
},
{
"name" : " test2 " ,
"function" : false
}
]
} Dynamisch beladene Befehle werden durch den Dateinamen mit einem Präfix von "Zzz__" bezeichnet. In einem Befehlsmodul gibt es eine Funktion als command . Diese Funktion wird dem Funktionsattribut eines Command zugeordnet und für die Ausführung im Speicher gespeichert. Die Funktion hat Zugriff auf alle Argumente, die analysiert wurden, sowie auf KWARGs:
' Selbst ' ( Command ), in dem die Metadaten für den Befehl untergebracht sind, der ausgeführt wird.
' Parser ' ( CommandParser ), das die Liste der registrierten Befehle und Befehlsdaten speichert.
' Kontext ' ( CommandContext ), das die CommandSource und den ursprünglichen Text zur Parsen versorgt.
CommandParser.parse(context: CommandContext, **kwargs) . Da Befehle ihre eigenen Module nicht importieren können, sind einige in Global ( math , random und string ) enthalten. Weitere im globalen Bereich enthaltene Attribute sind: getitem ( Operator.getItem ) und ImproperUsageError ( dyncommands.exceptions.improperusageError ).
def command ( * args , ** kwargs ):
self , context = kwargs . pop ( 'self' ), kwargs . pop ( 'context' )
source = context . source
if len ( args ) == 2 :
amount , sides = abs ( int ( getitem ( args , 0 ))), abs ( int ( getitem ( args , 1 )))
if amount > 0 and sides > 0 :
dice_rolls = [ f" { ( str ( i + 1 ) + ':' ) if amount > 1 else '' } { str ( random . randint ( 1 , sides )) } / { sides } " for i in range ( amount )]
source . send_feedback ( f"/me U0001f3b2 { source . display_name } rolled { 'a die' if amount == 1 else str ( amount ) + ' dice' } with { sides } side { '' if sides == 1 else 's' } : { ', ' . join ( dice_rolls ) } U0001f3b2 " )
else :
raise ImproperUsageError ( self , context )
else :
raise ImproperUsageError ( self , context ) Sie können jederzeit CommandParser.reload() aufrufen, um alle Befehlsmodule und Metadaten aus dem Speicher Speicher neu zu laden.
../
│
├───[commands_path]/
│ ├─── commands.json
│ ├─── zzz__[command1].py
│ ├─── zzz__[command2].py
│ └─── zzz__[command3].py
│
Um Befehle hinzuzufügen, können Sie entweder Daten in eine commands.json -Datei eingeben oder die Methode CommandParser.add_command(text: str, link: bool = False, **kwargs) verwenden. Der einfachste Weg, diese Methode zu verwenden, besteht darin, das Befehlsmodul als Text zu lesen und diese an das erste Argument zu übergeben. Sie können auch Befehlsmodule online speichern, um eine Remote -Installation zu ermöglichen. Wenn Sie den Link -Parameter auf True festlegen, wird Text als Link gelesen und die Rohtextdaten von diesem Link abgerufen. Beispiel: Gist und Pastebin.
Hinweis: Beim Hinzufügen eines Befehls muss Metadaten für 'Name' gefüllt werden. Dies kann in Form von Kommentaren erfolgen.
Das Entfernen eines bereits hinzugefügten Befehls ist relativ einfach. Rufen Sie einfach CommandParser.remove_command(name: str)
Wenn Sie den Befehl beim Entfernen nicht löschen möchten, besteht eine bessere Alternative darin, ihn mit CommandParser.set_disabled(name: str, value: bool) zu deaktivieren.
# Name: points
# Usage: points [get (username:string) | set (username:string amount:integer)]
# Description: Get your current points
# Permission: 0
# Children: [{'name': 'get', 'usage': 'get (username:string)', 'permission':0}, {'name': 'set', 'usage': 'set (username:string amount:integer)', 'permission':500}]
def command ( * args , ** kwargs ):
... parser = CommandParser ( './' )
with open ( 'some_metadata.json' ) as _file :
get_ = { 'name' : 'get' , 'usage' : 'get (username:string)' , 'permission' : 0 }
set_ = { 'name' : 'set' , 'usage' : 'set (username:string amount:integer)' , 'permission' : 500 }
children = [ get_ , set_ ]
parser . add_command ( _file . read (), name = 'my-command' , description = 'Command with child commands.' , children = children ) parser = CommandParser ( './' )
with open ( 'some_metadata.json' ) as _file :
metadata = json . load ( _file )
parser . add_command ( 'https://gist.github.com/random/892hdh2fh389x0wcmksio7m' , link = True , ** metadata ) Der Dyncommand CommandParser unterstützt nativ nativ mit der Handhabung der Berechtigungsstufe, sodass Sie in jeder Befehlsfunktion kein ähnliches System implementieren müssen.
Jeder Befehl hat die Metadatenwert permission (mit Ausnahme des Sonderwerts -1 ) ist die minimale Berechtigungsstufe, die aus der CommandSource erforderlich ist. -1 stellt eine "unendliche" Anforderung dar, wobei keine CommandSource in der Lage ist, sie auszuführen, während das Berechtigungssystem aktiv ist.
Um das Berechtigungssystem zu deaktivieren, setzen Sie das Attribut CommandParser _ignore_permission auf true. Hinweis: Da dieses Attribut mit einem "_" beginnt, führt das Versuch, es von der Funktion eines Befehls zu ändern, zu einer fehlgeschlagenen Zusammenstellung und einer Ausnahme.