6

Birbirinden farklı komutlarla büyük bir CLI uygulamasına sahip olduğumu düşünün (örneğin, görüntü-magick gibi). Tıkla CLI uygulamaları ile Flask gelen "uygulama fabrika" desen kullanmak mümkün mü?

Ben modüller halinde bu uygulamayı organize etmek istedik ve vs Yani, bir yerde bir ana click.group olacağını:

from main import my_app 

# command_x.py 
@my_app.command() 
def command_x(): 
    pass 
: bir komut tanımlamak her modülde alınabilir

#main.py file 
@click.group() 
def my_app(): 
    pass 

if __name__ == "__main__": 
    my_app() 

Sorun şu ki, main.py dosyası command_x.py hakkında hiçbir şey bilmediğinden ve temel bölümü çağırmadan önce içe aktarmam gerekeceğinden, döngüsel bir içe aktarma sorunuyla karşılaşıyorum.

Bu, Flask'ta da olur ve genellikle uygulama fabrika düzeniyle ilgilenir. Genellikle görünümler önce oluşturulan uygulamaya sahip olacaktır:

# blueprints.py 
blueprint = Blueprint(yaddayadda) 

@blueprint.route("/") 
def view_x(): 
    pass 

Ve nasıl oluşturulacağını bilen bir fabrika yapmak: Eğer planları arasında "kayıt" erteleme uygulaması fabrika deseni olarak

app = Flask("my_app") 

@my_app.route("/") 
def view_x(): 
    pass 

if __name__ == "__main__": 
    app.run() 

Uygulamanın ve planları kayıt:

#app_factory.py 
from blueprints import view_x 

def create_app(): 
    app = Flask() 
    view_x.init_app(app) 
    return app 

ve sonra uygulamayı çalıştırmak için bir komut dosyası oluşturabilirsiniz:

#main.py 

from app_factory import create_app 

if __name__ == "__main__": 
    app = create_app() 
    app.run() 

Benzer bir desen Tıklamada kullanılabilir mi? Tek tek komutlar olan "denetleyicileri" kaydeddiğim bir "tıklama uygulaması" (belki de click.Group'u uzatabilir miyim) oluşturabilir miyim?

cevap

1

Tamam, biraz düşündüm ve şu işe yarayacak gibi görünüyor. Muhtemelen son bir çözüm değil ama ilk adım gibi görünüyor.

# my_click_classes.py 

import click 

class ClickApp(click.MultiCommand): 

    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     self.commands = {} 

    def add_command(self, command_name, command): 
     self.commands.update({command_name: command}) 

    def list_commands(self, ctx): 
     return [name for name, _ in self.commands.items()] 

    def get_command(self, ctx, name): 
     return self.commands.get(name) 

Ve Komut sınıfını:

# commands.py 

from my_click_classes import command 

@command 
def run(): 
    print("run!!!") 

@command 
def walk(): 
    print("walk...") 

ve:

class MyCommand(click.Command): 

    def init_app(self, app): 
     return app.add_command(self.name, self) 

def mycommand(*args, **kwargs): 
    return click.command(cls=MyCommand) 

Bu komutlar ayrı modüllerde tanımladığınız sağlar

Ben MultiCommand sınıfını uzatabilirsiniz Ayrılmış bir modülde "uygulama":

Hatta "uygulama fabrikası" desenini de kullanabilirsiniz.

Belki de kesin bir çözüm değil. İyileştirmenin herhangi bir yolunu görebilirseniz, lütfen bize bildirin.

3

Belki geç kaldı, ancak modülleri ayırmak için de bir çözüm arayacaktım. Basitçe modüllerden komutları enjekte etmek bir dekoratör kullanın:

#main.py file 
import click 
import commands 

def lazyloader(f): 
    # f is an instance of click.Group 
    f.add_command(commands.my_command) 
    return f 

@lazyloader 
@click.group() 
def my_app(): 
    pass 

if __name__ == "__main__": 
    my_app() 

ayrılmış komut tıklamadan zamanki dekoratörler kullanabilirsiniz.

#commands.py 
import click 

@click.command() 
def my_command(): 
    pass