Eksekusi Perintah Dinamis, Parsing, dan Penyimpanan.
DynCommands memungkinkan Anda untuk mengimpor dan menjalankan fungsi Python secara dinamis. Berguna untuk menambahkan perintah ke chatbots IRC atau aplikasi CLI tanpa restart.
Saat mem -parsing string, itu memisahkan nama perintah dari argumen, dan menjalankan fungsi tersimpan dengan argumen tersebut. Setiap kali parser dipanggil, Anda dapat meneruskan kwarg khusus Anda sendiri yang akan diakses oleh perintah tersebut.
Semua modul perintah dikompilasi melalui OppateTyPython sebelum diizinkan untuk dijalankan. Anda dapat mematikan eksekusi terbatas dengan mengatur CommandParser._unrestricted to true , meskipun ini sangat tidak disarankan saat menjalankan kode yang tidak dipercaya.
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' Metadata untuk perintah disimpan dalam file commands.json dari direktori CommandParser.commands_path . Di sinilah semua data untuk parser dimuat dan disimpan.
Semua file commands.json divalidasi dengan skema JSON melalui paket jsonschema python
| kunci | jenis | keterangan | bawaan | diperlukan |
|---|---|---|---|---|
commandPrefix | rangkaian | String harus dimulai dengan awalan ini, jika tidak ia diabaikan. String kosong menerima semua. | N/a | Ya |
commands | array [ perintah ] | Berisi metadata untuk modul perintah yang disimpan. | N/a | Ya |
| kunci | jenis | keterangan | bawaan | diperlukan |
|---|---|---|---|---|
name | rangkaian | Secara unik mengidentifikasi perintah ke commandparser. | N/a | Ya |
usage | rangkaian | Informasi Penggunaan (Cara Menggunakan Args). | "" | TIDAK |
description | rangkaian | Deskripsi perintah. | "" | TIDAK |
permission | bilangan bulat | Tingkat izin yang diperlukan CommandSource untuk menjalankan perintah. | 0 | TIDAK |
function | Boolean , null | Apakah ada modul python terkait untuk dimuat. | batal | TIDAK |
children | array [ perintah ] | Sub-Komandan; Ini ditangani oleh fungsi orang tua. (Tidak ada modul terkait untuk diri mereka sendiri). | [] | TIDAK |
overridable | Boolean | Apakah CommandParser dapat mengganti data apa pun di dalam objek ini (harus diaktifkan secara manual). | BENAR | TIDAK |
disabled | Boolean | Jika True Still Load Command, tetapi Naikkan DisableDerror saat mencoba mengeksekusi. | PALSU | TIDAK |
CATATAN: Modul perintah tidak dimuat kecuali mereka terdaftar di commands.json dengan tombol function diatur ke True .
commands.json Isi: {
"commandPrefix" : " ! " ,
"commands" : [
{
"name" : " test " ,
"usage" : " test [*args:any] " ,
"description" : " Test command. " ,
"permission" : 500 ,
"function" : true
},
{
"name" : " test2 " ,
"function" : false
}
]
} Perintah yang dimuat secara dinamis dilambangkan dengan nama file dengan awalan "zzz__". Di dalam modul perintah, ada fungsi yang didefinisikan sebagai command . Fungsi ini akan dipetakan ke atribut fungsi Command dan disimpan dalam memori untuk dieksekusi. Fungsi ini memiliki akses ke arg apa pun yang diuraikan, serta kwargs:
' Self ' ( Command ), yang menampung metadata untuk perintah yang sedang dieksekusi.
' Parser ' ( CommandParser ), yang menyimpan daftar perintah terdaftar dan data perintah.
' Context ' ( CommandContext ), yang memasok CommandSource dan teks asli yang dikirim untuk parsing.
CommandParser.parse(context: CommandContext, **kwargs) . Karena perintah tidak dapat mengimpor modul mereka sendiri, beberapa termasuk dalam global ( math , random , dan string ). Atribut lain yang termasuk dalam ruang lingkup global adalah: getitem ( operator.getItem ), dan 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 ) Kapan saja, Anda dapat menghubungi CommandParser.reload() untuk memuat ulang semua modul perintah dan metadata dari penyimpanan disk.
../
│
├───[commands_path]/
│ ├─── commands.json
│ ├─── zzz__[command1].py
│ ├─── zzz__[command2].py
│ └─── zzz__[command3].py
│
Untuk menambahkan perintah, Anda dapat memasukkan data secara manual ke file commands.json , atau menggunakan metode CommandParser.add_command(text: str, link: bool = False, **kwargs) . Cara termudah untuk menggunakan metode ini adalah dengan membaca modul perintah sebagai teks dan meneruskannya ke argumen pertama. Anda juga dapat menyimpan modul perintah secara online untuk memungkinkan instalasi jarak jauh, karena mengatur parameter tautan ke true akan membaca teks sebagai tautan, dan akan mendapatkan data teks mentah dari tautan itu. Mis: GIST DAN PASTEBIN.
Catatan: Saat menambahkan perintah, metadata untuk 'nama' harus diisi. Ini dapat dilakukan dalam bentuk komentar.
Menghapus perintah yang sudah ditambahkan relatif mudah. Cukup hubungi CommandParser.remove_command(name: str) dengan nama perintah yang ingin Anda hapus, dan itu akan menghapus metadata dan modul perintah dari disk.
Jika Anda tidak ingin menghapus perintah saat menghapus, alternatif yang lebih baik adalah menonaktifkannya dengan CommandParser.set_disabled(name: str, value: bool) .
# 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 ) DynCommand CommandParser secara asli mendukung penanganan level izin, jadi Anda tidak perlu menerapkan sistem serupa di setiap fungsi perintah.
Setiap perintah memiliki permission nilai metadata, (dengan pengecualian nilai khusus -1 ) adalah tingkat izin minimum yang diperlukan dari CommandSource . -1 mewakili persyaratan "tak terbatas", di mana tidak ada CommandSource akan dapat melaksanakannya saat sistem izin aktif.
Untuk menonaktifkan sistem izin, atur atribut _ignore_permission CommandParser ke True. Catatan: Karena atribut ini dimulai dengan "_", mencoba mengubahnya dari dalam fungsi perintah akan menghasilkan kompilasi yang gagal dan pengecualian.