Veuillez me demander comment passer un paramètre défini par l'utilisateur à partir de la ligne de commande et du fichier de configuration setup.cfg au script setup.py de distutils. Je veux écrire un script setup.py, qui accepte les paramètres spécifiques à mon package. Par exemple:
python setup.py install -foo myfoo
Merci,
Mher
Comme Setuptools/Distuils sont horriblement documentés, j'ai eu du mal à trouver la réponse à cela moi-même. Mais finalement, je suis tombé sur l'exemple this . En outre, this une question similaire a été utile. Fondamentalement, une commande personnalisée avec une option ressemblerait à:
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,
}
)
Voici une solution très simple, tout ce que vous avez à faire est de filtrer sys.argv
Et de le gérer vous-même avant d'appeler distutils setup(..)
. Quelque chose comme ça:
if "--foo" in sys.argv:
do_foo_stuff()
sys.argv.remove("--foo")
...
setup(..)
La documentation sur la façon de le faire avec des distutils est terrible, j'ai finalement trouvé celui-ci: le guide des auto-stoppeurs pour l'emballage , qui utilise sdist
et son user_options
. Je trouve la référence extension distutils pas particulièrement utile.
Bien que cela ressemble à la façon "correcte" de le faire avec des distutils (au moins la seule que j'ai pu trouver qui soit vaguement documentée). Je n'ai rien trouvé sur les commutateurs --with
Et --without
Mentionnés dans l'autre réponse.
Le problème avec cette solution distutils est qu'elle est bien trop impliquée pour ce que je recherche (ce qui peut aussi être le cas pour vous). Ajouter des dizaines de lignes et sous-classer sdist
est juste mal pour moi.
Oui, nous sommes en 2015 et la documentation pour ajouter des commandes et des options dans setuptools
et distutils
est encore largement manquante.
Après quelques heures frustrantes, j'ai trouvé le code suivant pour ajouter une option personnalisée à la commande install
de 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)
Il convient de mentionner que install.run () vérifie s'il est appelé "nativement" ou s'il a été corrigé:
if not self._called_from_setup(inspect.currentframe()):
orig.install.run(self)
else:
self.do_Egg_install()
À ce stade, vous enregistrez votre commande avec setup
:
setup(
cmdclass={
'install': InstallCommand,
},
:
Vous ne pouvez pas vraiment transmettre de paramètres personnalisés au script. Cependant, les choses suivantes sont possibles et pourraient résoudre votre problème:
--with-featurename
, les fonctionnalités standard peuvent être désactivées à l'aide de --without-featurename
. [AFAIR cela nécessite des setuptools]set
sous Windows alors que leur préfixe fonctionne sous linux/OS X (FOO=bar python setup.py
).cmd_class
es qui peut implémenter de nouvelles fonctionnalités. Ils sont également chaînables, vous pouvez donc l'utiliser pour changer des variables dans votre script. (python setup.py foo install
) exécutera la commande foo
avant d'exécuter install
.J'espère que cela aide en quelque sorte. D'une manière générale, je suggère de fournir un peu plus d'informations sur ce que devrait exactement faire votre paramètre supplémentaire, peut-être existe-t-il une meilleure solution.
Peut-être que vous êtes un programmeur non chevronné comme moi qui a toujours eu du mal après avoir lu toutes les réponses ci-dessus. Ainsi, vous pourriez trouver un autre exemple potentiellement utile ( et pour répondre aux commentaires dans les réponses précédentes sur la saisie des arguments de ligne de commande ):
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,
},
Ce qui précède est testé et à partir d'un code que j'ai écrit. J'ai également inclus des docstrings légèrement plus détaillés pour rendre les choses plus faciles à comprendre.
Quant à la ligne de commande: python setup.py runClient --socket=127.0.0.1:7777
. Une double vérification rapide à l'aide d'instructions print montre qu'en effet l'argument correct est récupéré par la méthode run.
Autres ressources que j'ai trouvées utiles ( plus et plus exemples):
commandes distutils personnalisées
https://seasonofcode.com/posts/how-to-add-custom-build-steps-and-commands-to-setuppy.html
J'ai utilisé avec succès une solution de contournement pour utiliser une solution similaire à la suggestion de totaam. J'ai fini par faire apparaître mes arguments supplémentaires dans la liste 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(...)
Une validation supplémentaire pourrait être ajoutée pour s'assurer que les entrées sont bonnes, mais c'est comme ça que je l'ai fait
Un moyen rapide et facile similaire à celui donné par totaam serait d'utiliser argparse pour saisir l'argument -foo et laisser les arguments restants pour l'appel à distutils.setup (). Utiliser argparse pour cela serait préférable à une itération via sys.argv manuellement à mon humble avis. Par exemple, ajoutez ceci au début de votre 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
Le add_help=False
l'argument signifie que vous pouvez toujours obtenir l'aide régulière de setup.py en utilisant -h
(à condition de --foo
est donné).
Pour être entièrement compatible avec les deux python setup.py install
et pip install .
vous devez utiliser des variables d'environnement car pip
option --install-option=
est buggé:
--install-option
fuites sur les lignesCeci est un exemple complet n'utilisant pas le --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',
...
)
Ensuite, vous pouvez l'exécuter comme ceci sous 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
Mais, si vous êtes sous Windows, exécutez-le comme ceci:
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
Références: