Структура пакета, который также может быть запущен как скрипт командной строки - PullRequest
0 голосов
/ 20 декабря 2018

Я написал пакет с 'стандартной' минимальной структурой .Это выглядит так:

my_package/
    my_package/
        __init__.py
    setup.py

__init__.py содержит класс и поэтому может быть просто импортирован и использован, как и следовало ожидать.

Однако код действительно пригоден для использования в командной строке, например,

python my_package --arg1 "I like bananas."

Сначала у меня только что была if __name__ == '__main__' проверка __init__, котораябудет затем использовать argparse.Это работает , но это не красиво, потому что это будет означать, что вы будете вызывать его из командной строки следующим образом:

python my_package/__init__.py --arg1 "I like bananas."

Из того, что я прочитал, это гдеВходит файл __main__.py, который будет выполняться как скрипт по умолчанию внутри папки (аналогично файлу index.html на веб-сайте).У меня есть идея просто импортировать __init__.py, запустить argparse и передать аргументы в конструктор класса.Вот так:

import argparse
from __init__ import MyClass

parser = argparse.ArgumentParser()
parser.add_argument("--arg1", help="Some dummy value")

args = parser.parse_args()
my_class = MyClass(**vars(args))
my_class.do_stuff()

Так должны быть структурированы подобные пакеты, или есть лучший способ?


Выше работает , но PyCharm сообщаетмне, что в __main__.py __init__ это неразрешенная ссылка.То же самое для MyClass в этой строке импорта.Когда вместо этого я использую .__init__ (с точкой), предупреждение исчезает, но затем код больше не работает, давая мне ImportError: attempted relative import with no known parent package.

1 Ответ

0 голосов
/ 23 декабря 2018

Я хочу предложить вам другую структуру:

my_package/
    my_package/
        __init__.py
        cli_scripts.py
    setup.py

Давайте предположим, что ваш __init__.py выглядит следующим образом (в качестве примечания я бы рекомендовал перенести определенные в нем классы в отдельноеfile, а затем просто импортируйте этот файл в __init__):

class Test(object):

    def __init__(self, a)
        self.a = a

    def __call__(self):
        print(self.a)

Теперь в пакете есть дополнительный файл, который использует материал, реализованный в пакете, назовем его cli_scripts.py:

import argparse

from my_package import Test


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("a", type=int, help="Just an example argument")
    return parser.parse_args()

def demonstration():
    args = parse_args()
    t = Test(a=args.a)
    t()

Теперь я предлагаю использовать console_scripts точку входа внутри setup.py, которая теперь может выглядеть примерно так:

from setuptools import setup

setup(
    name='testpy',
    version='0.1',
    description='Just an example',
    author='RunOrVeith',
    author_email='xyz@mailinator.com',
    packages=["my_package"],
    entry_points={
        "console_scripts": ["mypkg=my_package.cli_scripts:demonstration"]},
    install_requires=[],
)

Теперь, когда вызапустите pip install . внутри папки my_package верхнего уровня, ваш пакет будет установлен.entry_points автоматически генерирует для вас исполняемый файл, который вы теперь можете вызывать с именем, которое вы дали ему внутри setup.py, в данном примере mypkg.Это означает, что теперь вы можете запустить

mypkg 5, и это будет вызывать demonstration().

Таким образом:

  • вам не нужно обрабатывать __main__ файлы
  • , вы можете дать своему сценарию осмысленное имя
  • youвам не нужно заботиться о том, является ли ваш скрипт исполняемым, или указать, что скрипт должен запускаться с python
  • , вы можете иметь столько списков, сколько захотите, внутри списка entry_points
  • это заставляет вас писать функции, которые вы также можете вызывать из других модулей, вместо __main__

Я думаю, что это довольно чисто.Вы можете прочитать больше о entry_points в этом блоге , он имеет больше функциональных возможностей!Если вы хотите использовать код, указанный в __main__ вместо этого cli_scripts подхода, вы можете взглянуть на этот вопрос .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...