distutils: как передать пользовательский параметр в setup.py? - PullRequest
58 голосов
/ 24 марта 2009

Подскажите, пожалуйста, как передать пользовательский параметр как из командной строки, так и из файла конфигурации setup.cfg в скрипт dist.tils setup.py. Я хочу написать скрипт setup.py, который принимает параметры, специфичные для моего пакета. Например:

python setup.py install -foo myfoo

Спасибо,
Мгер

Ответы [ 8 ]

56 голосов
/ 27 ноября 2013

Поскольку Setuptools / Distuils ужасно задокументированы, у меня возникли проблемы с поиском ответа на этот вопрос. Но в конце концов я наткнулся на этот пример. Также, этот похожий вопрос был полезен. По сути, пользовательская команда с параметром будет выглядеть так:

from distutils.core import setup, Command

class InstallCommand(Command):
    description = "Installs the foo."
    user_options = [
        ('foo=', None, 'Specify the foo to bar.'),
    ]
    def initialize_options(self):
        self.foo = None
    def finalize_options(self):
        assert self.foo in (None, 'myFoo', 'myFoo2'), 'Invalid foo!'
    def run(self):
        install_all_the_things()

setup(
    ...,
    cmdclass={
        'install': InstallCommand,
    }
)
25 голосов
/ 25 января 2011

Вот очень простое решение, все, что вам нужно сделать, это отфильтровать sys.argv и обработать его самостоятельно перед вызовом distutils setup(..). Примерно так:

if "--foo" in sys.argv:
    do_foo_stuff()
    sys.argv.remove("--foo")
...
setup(..)

Документация о том, как сделать это с distutils, ужасна, в конце концов я наткнулся на это: руководство автостопщиков по упаковке , в которой используется sdist и user_options Я считаю, что ссылка расширяющий distutils не особенно полезна.

Хотя это выглядит как «правильный» способ сделать это с помощью distutils (по крайней мере, единственный, который я смог найти, смутно задокументирован). Я не смог найти ничего на --with и --without переключателях, упомянутых в другом ответе.

Проблема с этим решением distutils заключается в том, что оно слишком сильно связано с тем, что я ищу (что также может иметь место для вас). Добавление десятков строк и подклассов sdist просто неправильно для меня.

16 голосов
/ 17 октября 2015

Да, это 2015, и документация для добавления команд и опций в setuptools и distutils по-прежнему в основном отсутствует.

Через несколько часов я нашел следующий код для добавления пользовательской опции в команду install setup.py:

from setuptools.command.install import install


class InstallCommand(install):
    user_options = install.user_options + [
        ('custom_option=', None, 'Path to something')
    ]

    def initialize_options(self):
        install.initialize_options(self)
        self.custom_option = None

    def finalize_options(self):
        #print('The custom option for install is ', self.custom_option)
        install.finalize_options(self)

    def run(self):
        global my_custom_option
        my_custom_option = self.custom_option
        install.run(self)  # OR: install.do_egg_install(self)

Стоит отметить, что install.run () проверяет, называется ли он «изначально» или был исправлен:

if not self._called_from_setup(inspect.currentframe()):
    orig.install.run(self)
else:
    self.do_egg_install()

На этом этапе вы регистрируете свою команду с помощью setup:

setup(
    cmdclass={
        'install': InstallCommand,
    },
    :
11 голосов
/ 25 марта 2009

Вы не можете передать пользовательские параметры в скрипт. Однако следующие вещи возможны и могут решить вашу проблему:

  • дополнительные функции можно включить с помощью --with-featurename, стандартные функции можно отключить с помощью --without-featurename. [AFAIR это требует setuptools]
  • вы можете использовать переменные окружения, однако для Windows они должны быть set, тогда как их префикс работает в linux / OS X (FOO=bar python setup.py).
  • вы можете расширять distutils своими cmd_class, которые могут реализовывать новые функции. Они также являются цепочечными, так что вы можете использовать это для изменения переменных в вашем скрипте. (python setup.py foo install) выполнит команду foo перед выполнением install.

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

5 голосов
/ 08 апреля 2016

Возможно, вы не опытный программист, как я, который все еще боролся после прочтения всех ответов выше. Таким образом, вы могли бы найти другой пример, потенциально полезный ( и адрес комментариев в предыдущих ответах о вводе аргументов командной строки ):

class RunClientCommand(Command):
    """
    A command class to runs the client GUI.
    """

    description = "runs client gui"

    # The format is (long option, short option, description).
    user_options = [
        ('socket=', None, 'The socket of the server to connect (e.g. '127.0.0.1:8000')',
    ]

    def initialize_options(self):
        """
        Sets the default value for the server socket.

        The method is responsible for setting default values for
        all the options that the command supports.

        Option dependencies should not be set here.
        """
        self.socket = '127.0.0.1:8000'

    def finalize_options(self):
        """
        Overriding a required abstract method.

        The method is responsible for setting and checking the 
        final values and option dependencies for all the options 
        just before the method run is executed.

        In practice, this is where the values are assigned and verified.
        """
        pass

    def run(self):
        """
        Semantically, runs 'python src/client/view.py SERVER_SOCKET' on the
        command line.
        """
        print(self.socket)
        errno = subprocess.call([sys.executable, 'src/client/view.py ' + self.socket])
        if errno != 0:
            raise SystemExit("Unable to run client GUI!")

setup(
    # Some other omitted details
    cmdclass={
        'runClient': RunClientCommand,
    },

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

Что касается командной строки: python setup.py runClient --socket=127.0.0.1:7777. Быстрая двойная проверка с использованием операторов print показывает, что метод run действительно выбирает правильный аргумент.

Другие ресурсы, которые я нашел полезными ( больше и больше примеров):

Пользовательские команды distutils

https://seasonofcode.com/posts/how-to-add-custom-build-steps-and-commands-to-setuppy.html

4 голосов
/ 04 февраля 2015

Я успешно использовал обходной путь, чтобы использовать решение, подобное предложению Totaam. В итоге я выдал свои дополнительные аргументы из списка sys.argv:

import sys
from distutils.core import setup
foo = 0
if '--foo' in sys.argv:
    index = sys.argv.index('--foo')
    sys.argv.pop(index)  # Removes the '--foo'
    foo = sys.argv.pop(index)  # Returns the element after the '--foo'
# The foo is now ready to use for the setup
setup(...)

Может быть добавлена ​​дополнительная проверка, чтобы убедиться, что входные данные хороши, но я так и сделал

1 голос
/ 22 сентября 2013

Быстрый и простой способ, подобный тому, который дает totaam, - использовать argparse для захвата аргумента -foo и оставить оставшиеся аргументы для вызова distutils.setup (). Использование argparse для этого было бы лучше, чем перебирать sys.argv вручную imho. Например, добавьте это в начале вашего setup.py:

argparser = argparse.ArgumentParser(add_help=False)
argparser.add_argument('--foo', help='required foo argument', required=True)
args, unknown = argparser.parse_known_args()
sys.argv = [sys.argv[0]] + unknown

Аргумент add_help=False означает, что вы все равно можете получить обычную справку setup.py, используя -h (при условии * --foo).

0 голосов
/ 24 мая 2019

Для полной совместимости с python setup.py install и pip install . необходимо использовать переменные окружения, поскольку pip опция --install-option= содержит ошибки:

  1. pip --install-option просачивается через строки
  2. Определите, что должно быть сделано - - (установить | глобальный) - вариант с колесами
  3. пункт не называет колеса abi3 правильно

Это полный пример, не использующий --install-option:

import os
environment_variable_name = 'MY_ENVIRONMENT_VARIABLE'
environment_variable_value = os.environ.get( environment_variable_name, None )

if environment_variable_value is not None:
    sys.stderr.write( "Using '%s=%s' environment variable!\n" % (
            environment_variable_name, environment_variable_value ) )

setup(
        name = 'packagename',
        version = '1.0.0',
        ...
)

Затем вы можете запустить его в Linux следующим образом:

MY_ENVIRONMENT_VARIABLE=1 pip install .
MY_ENVIRONMENT_VARIABLE=1 pip install -e .
MY_ENVIRONMENT_VARIABLE=1 python setup.py install
MY_ENVIRONMENT_VARIABLE=1 python setup.py develop

Но, если вы используете Windows, запустите ее так:

set "MY_ENVIRONMENT_VARIABLE=1" && pip install .
set "MY_ENVIRONMENT_VARIABLE=1" && pip install -e .
set "MY_ENVIRONMENT_VARIABLE=1" && python setup.py install
set "MY_ENVIRONMENT_VARIABLE=1" && python setup.py develop

Ссылки:

  1. Как получить аргументы, переданные в setup.py из pip с помощью '--install-option'?
  2. Передача аргументов командной строки в pip install
  3. Передача пути к библиотеке в качестве аргумента командной строки в setup.py
...