Подтвердить что ты не робот

Distutils: Как передать пользовательский параметр setup.py?

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

python setup.py install -foo myfoo

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

4b9b3361

Ответ 1

Поскольку 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,
    }
)

Ответ 2

Вот очень простое решение, все, что вам нужно сделать, это отфильтровать 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 для меня просто неверно.

Ответ 3

Да, это 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,
    },
    :

Ответ 4

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

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

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

Ответ 5

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

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. Быстрая двойная проверка с использованием операторов печати показывает, что действительно правильный аргумент подбирается методом run.

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

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

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

Ответ 6

Я успешно использовал обходное решение для использования решения, аналогичного предложению 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(...)

Некоторая дополнительная проверка может быть добавлена, чтобы обеспечить хорошие входы, но так я сделал это

Ответ 7

Быстрый и простой способ, подобный тому, который дал 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).

Ответ 8

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

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

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

import os
environment_variable_name = 'USE_STD_GETLINE'
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
  3. Передача пути к библиотеке в качестве аргумента командной строки в setup.py