Distutils: How to pass custom parameter setup.py?

Please tell me how to pass the user parameter from both the command line and the setup.cfg configuration file to setup.py script distutils. I want to write a setup.py script that accepts my package specific parameters. For example:

python setup.py install -foo myfoo 

Thank,
Mher

+57
python setup.py distutils
Mar 24 '09 at 14:12
source share
8 answers

Since Setuptools / Distuils is terribly documented, I had trouble finding an answer to it. But in the end, I came across this example. In addition, this one was useful. Basically, a user command with an option will look like this:

 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, } ) 
+55
Nov 27 '13 at 17:17
source share

Here is a very simple solution, all you have to do is filter out sys.argv and process it yourself before calling distutils setup(..) . Something like that:

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

The documentation on how to do this with distutils is terrible, in the end I came across this: a hitchhiking guide to packaging that uses sdist and its user_options . I find the distutils link not particularly useful.

Although this looks like the β€œright” way to do it with distutils (at least the only one I could find that is vaguely documented). I could not find anything in the --with and --without switches mentioned in another answer.

The problem with this distutils solution is that it is just too involved in what I'm looking for (which may be for you too). Adding dozens of lines and subclasses of sdist is simply wrong for me.

+23
Jan 25 2018-11-11T00:
source share

Yes, this is 2015 and the documentation for adding commands and options to setuptools and distutils is still mostly missing.

After several disappointing hours, I figured out the following code to add a custom option to the install setup.py command:

 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) 

It is worth noting that install.run () checks whether it was called "originally" or was fixed:

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

At this point, you register your command with setup :

 setup( cmdclass={ 'install': InstallCommand, }, : 
+15
Oct 17 '15 at 0:21
source share

You cannot pass custom parameters to a script. However, the following options are possible and may solve your problem:

  • additional functions can be enabled using --with-featurename , standard features can be disabled using --without-featurename . [AFAIR this requires setuptools]
  • you can use environment variables, however they must be set for windows, while their prefix works on linux / OS X ( FOO=bar python setup.py ).
  • you can extend distutils with your own cmd_class es, which can implement new features. They can also be grouped, so you can use them to change variables in a script. ( python setup.py foo install ) will execute the foo command before executing install .

Hope this helps. Generally speaking, I would like to offer a little more information on what exactly your additional parameter should do, perhaps there is a better solution.

+10
Mar 25 '09 at 6:48
source share

You may not be such a frustrated programmer as I, who still struggled after reading all the answers above. So you can find another potentially useful example ( and refer to the comments in previous answers about entering command line arguments ):

 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 (eg '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, }, 

The above testing is also from some code that I wrote. I have also included some more detailed documents to make it easier to understand.

Regarding the command line: python setup.py runClient --socket=127.0.0.1:7777 . A quick double check using print statements shows that the valid argument is matched by the run method.

Other resources I found useful ( more and more ):

User Distutils Commands

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

+4
Apr 08 '16 at 0:11
source share

I have successfully used a workaround to use a solution similar to the totaam suggestion. I ended up adding extra arguments from the sys.argv list:

 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(...) 

Some additional verification may be added to provide good inputs, but so I did it

+2
Feb 04 '15 at 19:29
source share

A quick and easy way, similar to the one that totaam gave, is to use argparse to capture the -foo argument and leave the remaining arguments to call distutils.setup (). Using argparse for this would be better than iterating through sys.argv manually by imho. For example, add this to the top of your 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 

The add_help=False argument means that you can still get the standard setup.py help with -h (if --foo provided).

0
Sep 22 '13 at 4:39 on
source share

For full compatibility with python setup.py install and pip install. you need to use envinroment variables because the pip parameter --install-option= contains errors:

  1. pip --install-option seeps through the lines
  2. Determine what needs to be done - (set | global) -option with wheels
  3. Pip incorrectly calls abi3 wheels

This is a complete example not using the --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', ... ) 

Then you can run it on Linux like this:

 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 

But, if you use Windows, run it like this:

 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 

Recommendations:

  1. How to get arguments passed to setup.py from pip using '--install -option'?
  2. Passing command line arguments to install pip
  3. Passing the library path as a command line argument to setup.py
-one
24 '19 at 2:32
source share



All Articles