18

I am using Python 2.7 with Distutils to distribute and install my self-created package. My setup.cfg looks like this:

[install]
prefix=/usr/local/MODULENAME
record=installation.txt

I have two questions:

  1. Is it possible to refer to variables set in setup.cfg (but also using command line options) when defining other setup.cfg options? For example, for:

    install-scripts=PREFIX/my-scripts
    

    I want PREFIX to be the prefix defined either inside setup.cfg or using --prefix command line argument, similar to the interpolation of variables when using ConfigParser.

  2. Is it possible to refer to the variables set in the setup.cfg from within my setup.py, without manually parsing the config file using ConfigParser?

Andrzej Pronobis
  • 33,828
  • 17
  • 76
  • 92
Naturjoghurt
  • 541
  • 6
  • 21
  • 1
    Out of curiosity, why do you not want to rely on `ConfigParser` for question `2)`? If relying on the python standard library is an issue, it is possible to parse through a config file using a simple, single-purpose parser written in your own module – NuclearPeon Jun 01 '15 at 19:26
  • @NuclearPeon `ConfigParser` will be useless if user provides (redefine) a prefix via CLI – zaufi Jun 02 '15 at 07:12
  • So correct me if I'm wrong, but you want a way to call `setup.py` so that it `1:` Reads the `setup.cfg` file and grabs all of its values, `2:` Associates the values in `setup.cfg` with the command line parameters of `setup.py` without using `ConfigParser` and `3:` runs the installation procedure. I just want to confirm your intentions before attempting to work on this problem. – NuclearPeon Jun 02 '15 at 16:09
  • 1
    @NuclearPeon, not quite like this... I just want to be able to access a real prefix (specified via CLI or from `setup.cfg` I don't care) from `setup.py`. I strongly believe it knows exacly where a user wants to install my package, so the question is _how can I access and use a real prefix_. It is quite typical for build systems (like CMake or autotools) or packaging tools (like RPM/DEB spec) you can easily access it anytime you want. Why there is no smth similar (or at least far from easy/obvious) for `setup.py`? – zaufi Jun 02 '15 at 22:29
  • I am not sure about # 1 but answer to question # 2 is NO. Without using CongigParser you can not reference the variables set in setup.cfg in setup.py. In any case this wont be best practice. – Pralhad Narsinh Sonar Jun 03 '15 at 18:21
  • Could you not just parse the ``setup.cfg`` in your ``setup.py``? It is afterall just a simple key/value configuration file with sections. The real question is what do you want to do once you have a nested dict of options? – James Mills Jun 04 '15 at 12:23
  • I want to know the real prefix, where a user decided to install my package. For example if it is `/usr`, then I need to install my config files to `/etc//`, otherwise to `${prefix}/etc//`. AFAIK, parsing `setup.cfg` would be useless if user has ability to override/specify another prefix via CLI of `setup.py` -- it is why I need to know the **real** prefix provided… – zaufi Jun 05 '15 at 00:26
  • @zaufi to quote you "I just want to be able to access a real prefix _specified via CLI or from setup.cfg I don't care_ but then you said that getting it from 'setup.cfg' is not an option because the user can give a prefix on the CLI so you do care ? you want the CLI to override the setup.cfg. – JamesD Jun 05 '15 at 09:59
  • @Guyver3, I meant that I don't care where this prefix came from (`setup.cfg` or CLI), I just want to use it (a real one) from `setup.py`… – zaufi Jun 05 '15 at 20:28
  • Based on the documentation, #1 does NOT seem possible. However, instead what you can do is define [Prefix] command then define the options under that if you want to organize it. The answer to the 2nd one is No. The .cfg is just a text file. – Hozikimaru Jun 05 '15 at 20:52
  • Regarding point `2)`, although it requires using configparser, you can use interpolation to reference other variables in the config file. https://docs.python.org/3/library/configparser.html#configparser.BasicInterpolation It looks like you are asking for a solution where `setup.py` automatically knows where the program it installed has been installed to (without ?) consulting cli or `setup.cfg`, similar to some sort of Windows Registry behaviour. Correct? – NuclearPeon Jun 07 '15 at 16:45

1 Answers1

12

Referring to Variables Inside setup.cfg

You can refer to other variables/options inside your setup.cfg file. The syntax is $variable, for instance:

[install]
prefix = /my/prefix
install-scripts = $base/scripts

Please note that I used $base since this variable is affected by your prefix settings provided both in the setup.cfg and using the setup.py install --prefix command line option. In this case, your scripts will be installed to /my/prefix/scripts unless the user specifies another prefix using command line.

It is possible to use $prefix inside setup.cfg as well, but this does not seem to be affected by the custom configuration.

Accessing Values of Variables Within setup.py (after setup())

It is also possible to read the values of all variables/options inside your setup.py. The function setup returns an instance of the class Distribution. That class holds all the values of variables grouped by the command (e.g. install) and you can obtain them using the get_option_dict method. For instance:

#!/usr/bin/env python

from distutils.core import setup

d = setup(
          # Here come your setup arguments
         )
print(d.get_option_dict('install'))

will print:

{'prefix': ('setup.cfg', '/my/prefix'), 
 'install_scripts': ('setup.cfg', '$base/scripts')}

Accessing Values of Variables Within setup.py (before setup())

It is also possible to obtain an instance of the class Distribution before setup() is even run. To do so, we can replicate what setup() is doing internally and build an instance of that class ourselves. Then, a decision about the value of setup arguments can be based on the value of some installation options. Let's look at an example:

from distutils.core import setup
from distutils.dist import Distribution

# Get our own instance of Distribution
dist = Distribution()
dist.parse_config_files()
dist.parse_command_line()

# Get prefix from either config file or command line
prefix = dist.get_option_dict('install')['prefix'][1]
print("Prefix is: " + prefix)

# Use the prefix to decide on the data path for data.txt
setup(data_files=[('/first/path/to/data' if prefix == '/some/prefix'
                                         else '/second/path/to/data',
                   ['data.txt'])])
Andrzej Pronobis
  • 33,828
  • 17
  • 76
  • 92
  • Thanks for the answer. But the problem is: I need to refer a prefix in a call to `setup()`… Example: `setup(..., data_files = [('/etc/mypkg' if prefix == '/usr' else prefix + '/etc/mypkg', ['config/mypkg.conf.sample'])], ...)` ... )` – zaufi Jun 06 '15 at 16:42
  • I added a solution to that as well. Please see my edit. – Andrzej Pronobis Jun 08 '15 at 18:37
  • **Great! Exactly what I wanted to find! Thanx a lot!** – zaufi Jun 08 '15 at 19:51
  • @AndrzejPronobis can I reference environment variables in my `setup.cfg` ? – red888 Jan 10 '23 at 18:47