Сменный шаблон подкоманды Python?

Я не думаю, что это когда-нибудь будет поддержано. GDI + очень специфичен для платформы Windows. Если вам нужна библиотека рисунков, вы можете взглянуть на SkiaSharp, который поддерживается Xamarin.

0
задан Johannes Ernst 19 January 2019 в 00:49
поделиться

3 ответа

Вы можете использовать функцию __import__ для динамического импорта модуля, используя имя строки, переданное в командной строке.

mod = sys.argv[1]
command =__import__(mod)
# assuming your pattern has a run method defined. 
command.run()

Обработка ошибок и т. Д. Оставлена ​​в качестве упражнения для читателя

Редактировать: Это будет зависеть от пользовательских плагинов, устанавливаемых через pip. Если вы хотите, чтобы пользователи добавляли плагины в папку без установки, вам нужно добавить эту папку в путь к Python.

0
ответ дан Josh J 19 January 2019 в 00:49
поделиться

Самый простой ответ: если все мои команды находятся в foo.commands:

import foo.commands
import importlib

for importer, modname, ispkg in pkgutil.iter_modules(foo.commands.__path__):
    mod=importlib.import_module('foo.commands.' + cmd)
    mod.run()

Это запустит все подкоманды. (Ну, в реальном коде я буду запускать только один. Это руководство.)

0
ответ дан Johannes Ernst 19 January 2019 в 00:49
поделиться

Хотя этот вопрос на самом деле довольно широк, в типовой установке Python по умолчанию (например, с setuptools) доступно достаточно инструментов, чтобы это было относительно достижимо, в том смысле, что оно действительно расширяемо, так что можно создавать другие пакеты / установлен таким образом, чтобы предоставлять новые обнаруживаемые подкоманды для вашей основной программы.

Ваш базовый пакет может предоставить стандартную точку входа в виде console_scripts , которая указывает на вашу точку входа, которая будет передавать все аргументы в экземпляр некоторого парсера аргументов (например, argparse ] ), и какой-то реестр, который вы можете реализовать по схеме, аналогичной console_scripts, за исключением вашей конкретной группы entry_points, чтобы она перебирала каждую запись и создавала объекты, которые также предоставляют свои собственные ArgumentParser. ] случаи, когда ваша основная точка входа будет динамически регистрироваться как подкоманда, показывая тем самым вашим пользователям, какие подкоманды действительно доступны и на что может быть похож их вызов.

Чтобы привести пример, в setup.py вашего основного пакета может быть такая запись, как

setup(
    name='my.package',
    # ...
    entry_points={
        'console_scripts': [
            'topcmd = my.package.runtime:main',
        ],
        'my.package.subcmd': [
            'subcmd1 = my.package.commands:subprog1',
            'subcmd2 = my.package.commands:subprog2',
        ],
    },
    # ...
)

Внутри исходного файла my/package/runtime.py метод main должен будет сконструировать новый Экземпляр ArgumentParser, и, повторяя точки входа, предоставленные pkg_resources.working_set, например:

from pkg_resources import working_set

def init_parser(argparser):  # pass in the argparser provided by main
    commands = argparser.add_subparsers(dest='command')
    for entry_point in working_set.iter_entry_points('my.package.subcmd'):
        subparser = commands.add_parser(entry_point.name)
        # load can raise exception due to missing imports or error in object creation
        subcommand = entry_point.load()
        subcommand.init_parser(subparser) 

Итак, в функции main созданный экземпляр argparser может быть передан в функцию, подобную той, что в выше, и точка входа 'subcmd1 = my.package.commands:subprog1' будет загружена. Внутри my/package/command.py должен быть реализован реализованный метод init_parser, который возьмет предоставленный подпарапетер и заполнит его необходимыми аргументами:

class SubProgram1(object):
    def init_parser(self, argparser)
        argparser.add_argument(...) 

subprog1 = SubProgram1() 

О, еще одна заключительная вещь, после передачи аргументов Основное argparser.parse_args(...) название команды предоставляется argparser.command. Должна быть возможность изменить это на фактический экземпляр, но это может или не может достичь того, чего вы точно хотите (потому что основная программа может захотеть выполнить дальнейшую работу / проверку перед фактическим использованием команды). Эта часть является еще одной сложной частью, но, по крайней мере, анализатор аргументов должен содержать информацию, необходимую для запуска правильной подпрограммы.

Естественно, это включает в себя абсолютно отсутствие проверки ошибок, и она должна быть реализована в некоторой форме, чтобы предотвратить сбои в работе основных программ из-за неисправных классов подкоманд. Я использовал такой шаблон (хотя и с гораздо более сложной реализацией), который может поддерживать произвольное количество вложенных подкоманд. Также пакеты, которые хотят реализовать пользовательские команды, могут просто добавить свою собственную запись в группу точек входа (в данном случае, в my.package.subcmd) для своих собственных setup.py. Например:

setup(
    name="some.other.package",
    # ...
    entry_points={
        'my.package.subcmd': [
            'extracmd = some.other.package.commands:extracmd',
        ],
    },
    # ...
)

Приложение:

В соответствии с запросом, фактическая реализация, используемая в производстве, находится в пакете ( quietjs ), который я сейчас поддерживаю. Установка этого пакета (в virtualenv) и запуск calmjs в командной строке должны отображать список подкоманд, идентичных записям, определенным в точках входа основного пакета . Установка дополнительного пакета, который расширяет функциональность (например, quietjs.webpack ) и повторный запуск calmjs, теперь перечислит calmjs.webpack в качестве дополнительной подкоманды.

Точки входа ссылаются на экземпляры подклассов к классу Runtime, и в нем есть место, где добавляется подпарсер и, если он удовлетворяет требованиям регистрации (многие следующие утверждения относятся к различным ошибкам / проверка работоспособности, например, что делать, когда несколько пакетов определяют одно и то же имя подкоманды для экземпляров среды выполнения, регистрирует для экземпляра argparser в этом конкретном экземпляре среды выполнения и передается подпарамер в метод init_argparser среды выполнения, которая инкапсулирует подкоманду. В качестве примера, подкомпонент подкоманды calmjs webpack устанавливается с помощью его метода init_argparser , и этот пакет регистрирует подкоманду webpack в своей собственной setup.py. (Чтобы поиграть с ними, просто используйте pip для установки соответствующих пакетов).

0
ответ дан metatoaster 19 January 2019 в 00:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: