• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""distutils.core
2
3The only module that needs to be imported to use the Distutils; provides
4the 'setup' function (which is to be called from the setup script).  Also
5indirectly provides the Distribution and Command classes, although they are
6really defined in distutils.dist and distutils.cmd.
7"""
8
9import os
10import sys
11
12from distutils.debug import DEBUG
13from distutils.errors import *
14
15# Mainly import these so setup scripts can "from distutils.core import" them.
16from distutils.dist import Distribution
17from distutils.cmd import Command
18from distutils.config import PyPIRCCommand
19from distutils.extension import Extension
20
21# This is a barebones help message generated displayed when the user
22# runs the setup script with no arguments at all.  More useful help
23# is generated with various --help options: global help, list commands,
24# and per-command help.
25USAGE = """\
26usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
27   or: %(script)s --help [cmd1 cmd2 ...]
28   or: %(script)s --help-commands
29   or: %(script)s cmd --help
30"""
31
32def gen_usage (script_name):
33    script = os.path.basename(script_name)
34    return USAGE % vars()
35
36
37# Some mild magic to control the behaviour of 'setup()' from 'run_setup()'.
38_setup_stop_after = None
39_setup_distribution = None
40
41# Legal keyword arguments for the setup() function
42setup_keywords = ('distclass', 'script_name', 'script_args', 'options',
43                  'name', 'version', 'author', 'author_email',
44                  'maintainer', 'maintainer_email', 'url', 'license',
45                  'description', 'long_description', 'keywords',
46                  'platforms', 'classifiers', 'download_url',
47                  'requires', 'provides', 'obsoletes',
48                  )
49
50# Legal keyword arguments for the Extension constructor
51extension_keywords = ('name', 'sources', 'include_dirs',
52                      'define_macros', 'undef_macros',
53                      'library_dirs', 'libraries', 'runtime_library_dirs',
54                      'extra_objects', 'extra_compile_args', 'extra_link_args',
55                      'swig_opts', 'export_symbols', 'depends', 'language')
56
57def setup (**attrs):
58    """The gateway to the Distutils: do everything your setup script needs
59    to do, in a highly flexible and user-driven way.  Briefly: create a
60    Distribution instance; find and parse config files; parse the command
61    line; run each Distutils command found there, customized by the options
62    supplied to 'setup()' (as keyword arguments), in config files, and on
63    the command line.
64
65    The Distribution instance might be an instance of a class supplied via
66    the 'distclass' keyword argument to 'setup'; if no such class is
67    supplied, then the Distribution class (in dist.py) is instantiated.
68    All other arguments to 'setup' (except for 'cmdclass') are used to set
69    attributes of the Distribution instance.
70
71    The 'cmdclass' argument, if supplied, is a dictionary mapping command
72    names to command classes.  Each command encountered on the command line
73    will be turned into a command class, which is in turn instantiated; any
74    class found in 'cmdclass' is used in place of the default, which is
75    (for command 'foo_bar') class 'foo_bar' in module
76    'distutils.command.foo_bar'.  The command class must provide a
77    'user_options' attribute which is a list of option specifiers for
78    'distutils.fancy_getopt'.  Any command-line options between the current
79    and the next command are used to set attributes of the current command
80    object.
81
82    When the entire command-line has been successfully parsed, calls the
83    'run()' method on each command object in turn.  This method will be
84    driven entirely by the Distribution object (which each command object
85    has a reference to, thanks to its constructor), and the
86    command-specific options that became attributes of each command
87    object.
88    """
89
90    global _setup_stop_after, _setup_distribution
91
92    # Determine the distribution class -- either caller-supplied or
93    # our Distribution (see below).
94    klass = attrs.get('distclass')
95    if klass:
96        del attrs['distclass']
97    else:
98        klass = Distribution
99
100    if 'script_name' not in attrs:
101        attrs['script_name'] = os.path.basename(sys.argv[0])
102    if 'script_args'  not in attrs:
103        attrs['script_args'] = sys.argv[1:]
104
105    # Create the Distribution instance, using the remaining arguments
106    # (ie. everything except distclass) to initialize it
107    try:
108        _setup_distribution = dist = klass(attrs)
109    except DistutilsSetupError as msg:
110        if 'name' not in attrs:
111            raise SystemExit("error in setup command: %s" % msg)
112        else:
113            raise SystemExit("error in %s setup command: %s" % \
114                  (attrs['name'], msg))
115
116    if _setup_stop_after == "init":
117        return dist
118
119    # Find and parse the config file(s): they will override options from
120    # the setup script, but be overridden by the command line.
121    dist.parse_config_files()
122
123    if DEBUG:
124        print("options (after parsing config files):")
125        dist.dump_option_dicts()
126
127    if _setup_stop_after == "config":
128        return dist
129
130    # Parse the command line and override config files; any
131    # command-line errors are the end user's fault, so turn them into
132    # SystemExit to suppress tracebacks.
133    try:
134        ok = dist.parse_command_line()
135    except DistutilsArgError as msg:
136        raise SystemExit(gen_usage(dist.script_name) + "\nerror: %s" % msg)
137
138    if DEBUG:
139        print("options (after parsing command line):")
140        dist.dump_option_dicts()
141
142    if _setup_stop_after == "commandline":
143        return dist
144
145    # And finally, run all the commands found on the command line.
146    if ok:
147        try:
148            dist.run_commands()
149        except KeyboardInterrupt:
150            raise SystemExit("interrupted")
151        except OSError as exc:
152            if DEBUG:
153                sys.stderr.write("error: %s\n" % (exc,))
154                raise
155            else:
156                raise SystemExit("error: %s" % (exc,))
157
158        except (DistutilsError,
159                CCompilerError) as msg:
160            if DEBUG:
161                raise
162            else:
163                raise SystemExit("error: " + str(msg))
164
165    return dist
166
167# setup ()
168
169
170def run_setup (script_name, script_args=None, stop_after="run"):
171    """Run a setup script in a somewhat controlled environment, and
172    return the Distribution instance that drives things.  This is useful
173    if you need to find out the distribution meta-data (passed as
174    keyword args from 'script' to 'setup()', or the contents of the
175    config files or command-line.
176
177    'script_name' is a file that will be read and run with 'exec()';
178    'sys.argv[0]' will be replaced with 'script' for the duration of the
179    call.  'script_args' is a list of strings; if supplied,
180    'sys.argv[1:]' will be replaced by 'script_args' for the duration of
181    the call.
182
183    'stop_after' tells 'setup()' when to stop processing; possible
184    values:
185      init
186        stop after the Distribution instance has been created and
187        populated with the keyword arguments to 'setup()'
188      config
189        stop after config files have been parsed (and their data
190        stored in the Distribution instance)
191      commandline
192        stop after the command-line ('sys.argv[1:]' or 'script_args')
193        have been parsed (and the data stored in the Distribution)
194      run [default]
195        stop after all commands have been run (the same as if 'setup()'
196        had been called in the usual way
197
198    Returns the Distribution instance, which provides all information
199    used to drive the Distutils.
200    """
201    if stop_after not in ('init', 'config', 'commandline', 'run'):
202        raise ValueError("invalid value for 'stop_after': %r" % (stop_after,))
203
204    global _setup_stop_after, _setup_distribution
205    _setup_stop_after = stop_after
206
207    save_argv = sys.argv.copy()
208    g = {'__file__': script_name}
209    try:
210        try:
211            sys.argv[0] = script_name
212            if script_args is not None:
213                sys.argv[1:] = script_args
214            with open(script_name, 'rb') as f:
215                exec(f.read(), g)
216        finally:
217            sys.argv = save_argv
218            _setup_stop_after = None
219    except SystemExit:
220        # Hmm, should we do something if exiting with a non-zero code
221        # (ie. error)?
222        pass
223
224    if _setup_distribution is None:
225        raise RuntimeError(("'distutils.core.setup()' was never called -- "
226               "perhaps '%s' is not a Distutils setup script?") % \
227              script_name)
228
229    # I wonder if the setup script's namespace -- g and l -- would be of
230    # any interest to callers?
231    #print "_setup_distribution:", _setup_distribution
232    return _setup_distribution
233
234# run_setup ()
235