Создание Python CLI: как правильно объявить entry_points в setuptools.setup - PullRequest
2 голосов
/ 17 октября 2019

Решено с использованием click вместо argparse, см. Ниже ..


Я создаю инструмент командной строки Python , следуя отличному учебнику Томасом Стрингером. Мой инструмент используется примерно так:

$ python rsearch.py -f foo -b bar

Я упаковал его с python setup.py sdist и python setup.py install, следуя документам . Все работает отлично! Теперь я устанавливаю его как pip пакет с pip install -e ., и мой исполняемый файл готов к работе, верно?

$ which rsearch
/usr/local/bin/rsearch

Проблема в

$ rsearch -f foo.txt -b bar/
Searching...
Searching... 
Found item from foo.txt in bar/path/to/target/
Searching...
Done!
Traceback (most recent call last):
  File "/usr/local/bin/rsearch", line 11, in <module>
    load_entry_point('rsearch', 'console_scripts', 'rsearch')()
TypeError: main() missing 2 required positional arguments: 'foo' and 'bar'

Я думаю, проблема в том, чтомои entry_points не указаны правильно:

from setuptools import setup
setup(
    name='rsearch',
    version='0.0.1',
    py_modules=['rsearch'],
    entry_points={
        'console_scripts': [
            'rsearch=rsearch.__main__:main'
        ]
    })

На основании учебного пособия, которому я следовал, хотя с 2016 года это должно работать. Я знаю, что distutils.core является предпочтительным setup() методом для Python 3.7, но я тоже это пробовал, и я получаю тот же результат.

My __main__.py выглядит следующим образом:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
    '--foo', 
    '-f',
    help='Foo help'
)
parser.add_argument(
    '--bar', 
    '-b', 
    help='Bar help'
)

def main(foi, gras):
    # code code code 
    # code code..

args = parser.parse_args()
main(args.foo, args.bar)

, и мой проект структурирован так:

rsearch
├── rsearch
│   └── __main__.py
└── setup.py

Примечание: скрипт Python работает так, как ожидается:

$ python __main__.py -f foo.txt -b bar/
Searching...
Searching... 
Found item from foo.txt in bar/path/to/target/
Searching...
Done!

Таким образом, сценарий не является проблемой. Эта ошибка возникает только при попытке запустить исполняемый файл, созданный с setuptools.setup()

Я использую Python 3.7.3 и pip 19.1.1. Любая помощь или предложения очень ценятся.


ОБНОВЛЕНИЕ

По предложению @ techouse, я реплицировал этот CLI, используя click и обновил назначение entry_points в setup.py, следуя их документация .

setup(
    name='rsearch',
    version='0.0.1',
    py_modules=['rsearch'],
    install_requires=[
        'Click',
    ],
    entry_points='''
        [console_scripts]
        rsearch=rsearch_script:cli
    ''',
)

Я переименовал скрипт в rsearch_script.py и использовал click декораторы вместо argparse:

@click.command()
@click.option('--foo', '-f')
@click.option('--bar', '-b')
def cli(foo, bar):
    # code code code
    # code code..

Я также переместилфайлы (из документации могут не иметь значения)

rsearch
├── rsearch_script.py
└── setup.py

В этом каталоге я запустил pip install -e . и бум!

Без ошибок, работает.

$ rsearch -f foo.txt -b bar
Searching...
Searching...

# ...

$ rsearch --help
Usage: rsearch [OPTIONS]

Options:
  -f, --foo TEXT
  -b, --bar TEXT
  --help

Спасибо за подсказку @techouse - Вы были правы, с этого момента я буду использовать Click для разработки Python CLI.

1 Ответ

0 голосов
/ 17 октября 2019

entry_points будет вызывать ваш main напрямую - это последний main в 'rsearch=rsearch.__main__:main'. Это означает, что код, который вызывает синтаксический анализатор args, никогда не вызывается, и, следовательно, вы получаете проблему с аргументами, которые никогда не передаются.

Не изменяйте ваш setup.py, а вместо этого перемещайте строку args = parser.parse_args()в функции main.

Условие if __name__ == __main__ будет выполняться только в том случае, если сценарий запускается непосредственно, как вы, и не при каких-либо других обстоятельствах.

...