ยปCore Development>Code coverage>Lib/packaging/dist.py

Python code coverage for Lib/packaging/dist.py

#countcontent
1n/a"""Class representing the project being built/installed/etc."""
2n/a
3n/aimport os
4n/aimport re
5n/a
6n/afrom packaging import logger
7n/afrom packaging.util import strtobool, resolve_name
8n/afrom packaging.config import Config
9n/afrom packaging.errors import (PackagingOptionError, PackagingArgError,
10n/a PackagingModuleError, PackagingClassError)
11n/afrom packaging.command import get_command_class, STANDARD_COMMANDS
12n/afrom packaging.command.cmd import Command
13n/afrom packaging.metadata import Metadata
14n/afrom packaging.fancy_getopt import FancyGetopt
15n/a
16n/a# Regex to define acceptable Packaging command names. This is not *quite*
17n/a# the same as a Python name -- leading underscores are not allowed. The fact
18n/a# that they're very similar is no coincidence: the default naming scheme is
19n/a# to look for a Python module named after the command.
20n/acommand_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
21n/a
22n/aUSAGE = """\
23n/ausage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
24n/a or: %(script)s --help [cmd1 cmd2 ...]
25n/a or: %(script)s --help-commands
26n/a or: %(script)s cmd --help
27n/a"""
28n/a
29n/a
30n/adef gen_usage(script_name):
31n/a script = os.path.basename(script_name)
32n/a return USAGE % {'script': script}
33n/a
34n/a
35n/aclass Distribution:
36n/a """Class used to represent a project and work with it.
37n/a
38n/a Most of the work hiding behind 'pysetup run' is really done within a
39n/a Distribution instance, which farms the work out to the commands
40n/a specified on the command line.
41n/a """
42n/a
43n/a # 'global_options' describes the command-line options that may be
44n/a # supplied to the setup script prior to any actual commands.
45n/a # Eg. "pysetup run -n" or "pysetup run --dry-run" both take advantage of
46n/a # these global options. This list should be kept to a bare minimum,
47n/a # since every global option is also valid as a command option -- and we
48n/a # don't want to pollute the commands with too many options that they
49n/a # have minimal control over.
50n/a global_options = [
51n/a ('dry-run', 'n', "don't actually do anything"),
52n/a ('help', 'h', "show detailed help message"),
53n/a ('no-user-cfg', None, 'ignore pydistutils.cfg in your home directory'),
54n/a ]
55n/a
56n/a # 'common_usage' is a short (2-3 line) string describing the common
57n/a # usage of the setup script.
58n/a common_usage = """\
59n/aCommon commands: (see '--help-commands' for more)
60n/a
61n/a pysetup run build will build the project underneath 'build/'
62n/a pysetup run install will install the project
63n/a"""
64n/a
65n/a # options that are not propagated to the commands
66n/a display_options = [
67n/a ('help-commands', None,
68n/a "list all available commands"),
69n/a ('use-2to3', None,
70n/a "use 2to3 to make source python 3.x compatible"),
71n/a ('convert-2to3-doctests', None,
72n/a "use 2to3 to convert doctests in separate text files"),
73n/a ]
74n/a display_option_names = [x[0].replace('-', '_') for x in display_options]
75n/a
76n/a # negative options are options that exclude other options
77n/a negative_opt = {}
78n/a
79n/a # -- Creation/initialization methods -------------------------------
80n/a def __init__(self, attrs=None):
81n/a """Construct a new Distribution instance: initialize all the
82n/a attributes of a Distribution, and then use 'attrs' (a dictionary
83n/a mapping attribute names to values) to assign some of those
84n/a attributes their "real" values. (Any attributes not mentioned in
85n/a 'attrs' will be assigned to some null value: 0, None, an empty list
86n/a or dictionary, etc.) Most importantly, initialize the
87n/a 'command_obj' attribute to the empty dictionary; this will be
88n/a filled in with real command objects by 'parse_command_line()'.
89n/a """
90n/a
91n/a # Default values for our command-line options
92n/a self.dry_run = False
93n/a self.help = False
94n/a for attr in self.display_option_names:
95n/a setattr(self, attr, False)
96n/a
97n/a # Store the configuration
98n/a self.config = Config(self)
99n/a
100n/a # Store the distribution metadata (name, version, author, and so
101n/a # forth) in a separate object -- we're getting to have enough
102n/a # information here (and enough command-line options) that it's
103n/a # worth it.
104n/a self.metadata = Metadata()
105n/a
106n/a # 'cmdclass' maps command names to class objects, so we
107n/a # can 1) quickly figure out which class to instantiate when
108n/a # we need to create a new command object, and 2) have a way
109n/a # for the setup script to override command classes
110n/a self.cmdclass = {}
111n/a
112n/a # 'script_name' and 'script_args' are usually set to sys.argv[0]
113n/a # and sys.argv[1:], but they can be overridden when the caller is
114n/a # not necessarily a setup script run from the command line.
115n/a self.script_name = None
116n/a self.script_args = None
117n/a
118n/a # 'command_options' is where we store command options between
119n/a # parsing them (from config files, the command line, etc.) and when
120n/a # they are actually needed -- ie. when the command in question is
121n/a # instantiated. It is a dictionary of dictionaries of 2-tuples:
122n/a # command_options = { command_name : { option : (source, value) } }
123n/a self.command_options = {}
124n/a
125n/a # 'dist_files' is the list of (command, pyversion, file) that
126n/a # have been created by any dist commands run so far. This is
127n/a # filled regardless of whether the run is dry or not. pyversion
128n/a # gives sysconfig.get_python_version() if the dist file is
129n/a # specific to a Python version, 'any' if it is good for all
130n/a # Python versions on the target platform, and '' for a source
131n/a # file. pyversion should not be used to specify minimum or
132n/a # maximum required Python versions; use the metainfo for that
133n/a # instead.
134n/a self.dist_files = []
135n/a
136n/a # These options are really the business of various commands, rather
137n/a # than of the Distribution itself. We provide aliases for them in
138n/a # Distribution as a convenience to the developer.
139n/a self.packages = []
140n/a self.package_data = {}
141n/a self.package_dir = None
142n/a self.py_modules = []
143n/a self.libraries = []
144n/a self.headers = []
145n/a self.ext_modules = []
146n/a self.ext_package = None
147n/a self.include_dirs = []
148n/a self.extra_path = None
149n/a self.scripts = []
150n/a self.data_files = {}
151n/a self.password = ''
152n/a self.use_2to3 = False
153n/a self.convert_2to3_doctests = []
154n/a self.extra_files = []
155n/a
156n/a # And now initialize bookkeeping stuff that can't be supplied by
157n/a # the caller at all. 'command_obj' maps command names to
158n/a # Command instances -- that's how we enforce that every command
159n/a # class is a singleton.
160n/a self.command_obj = {}
161n/a
162n/a # 'have_run' maps command names to boolean values; it keeps track
163n/a # of whether we have actually run a particular command, to make it
164n/a # cheap to "run" a command whenever we think we might need to -- if
165n/a # it's already been done, no need for expensive filesystem
166n/a # operations, we just check the 'have_run' dictionary and carry on.
167n/a # It's only safe to query 'have_run' for a command class that has
168n/a # been instantiated -- a false value will be inserted when the
169n/a # command object is created, and replaced with a true value when
170n/a # the command is successfully run. Thus it's probably best to use
171n/a # '.get()' rather than a straight lookup.
172n/a self.have_run = {}
173n/a
174n/a # Now we'll use the attrs dictionary (ultimately, keyword args from
175n/a # the setup script) to possibly override any or all of these
176n/a # distribution options.
177n/a
178n/a if attrs is not None:
179n/a # Pull out the set of command options and work on them
180n/a # specifically. Note that this order guarantees that aliased
181n/a # command options will override any supplied redundantly
182n/a # through the general options dictionary.
183n/a options = attrs.get('options')
184n/a if options is not None:
185n/a del attrs['options']
186n/a for command, cmd_options in options.items():
187n/a opt_dict = self.get_option_dict(command)
188n/a for opt, val in cmd_options.items():
189n/a opt_dict[opt] = ("setup script", val)
190n/a
191n/a # Now work on the rest of the attributes. Any attribute that's
192n/a # not already defined is invalid!
193n/a for key, val in attrs.items():
194n/a if self.metadata.is_metadata_field(key):
195n/a self.metadata[key] = val
196n/a elif hasattr(self, key):
197n/a setattr(self, key, val)
198n/a else:
199n/a logger.warning(
200n/a 'unknown argument given to Distribution: %r', key)
201n/a
202n/a # no-user-cfg is handled before other command line args
203n/a # because other args override the config files, and this
204n/a # one is needed before we can load the config files.
205n/a # If attrs['script_args'] wasn't passed, assume false.
206n/a #
207n/a # This also make sure we just look at the global options
208n/a self.want_user_cfg = True
209n/a
210n/a if self.script_args is not None:
211n/a for arg in self.script_args:
212n/a if not arg.startswith('-'):
213n/a break
214n/a if arg == '--no-user-cfg':
215n/a self.want_user_cfg = False
216n/a break
217n/a
218n/a self.finalize_options()
219n/a
220n/a def get_option_dict(self, command):
221n/a """Get the option dictionary for a given command. If that
222n/a command's option dictionary hasn't been created yet, then create it
223n/a and return the new dictionary; otherwise, return the existing
224n/a option dictionary.
225n/a """
226n/a d = self.command_options.get(command)
227n/a if d is None:
228n/a d = self.command_options[command] = {}
229n/a return d
230n/a
231n/a def get_fullname(self, filesafe=False):
232n/a return self.metadata.get_fullname(filesafe)
233n/a
234n/a def dump_option_dicts(self, header=None, commands=None, indent=""):
235n/a from pprint import pformat
236n/a
237n/a if commands is None: # dump all command option dicts
238n/a commands = sorted(self.command_options)
239n/a
240n/a if header is not None:
241n/a logger.info(indent + header)
242n/a indent = indent + " "
243n/a
244n/a if not commands:
245n/a logger.info(indent + "no commands known yet")
246n/a return
247n/a
248n/a for cmd_name in commands:
249n/a opt_dict = self.command_options.get(cmd_name)
250n/a if opt_dict is None:
251n/a logger.info(indent + "no option dict for %r command",
252n/a cmd_name)
253n/a else:
254n/a logger.info(indent + "option dict for %r command:", cmd_name)
255n/a out = pformat(opt_dict)
256n/a for line in out.split('\n'):
257n/a logger.info(indent + " " + line)
258n/a
259n/a # -- Config file finding/parsing methods ---------------------------
260n/a # XXX to be removed
261n/a def parse_config_files(self, filenames=None):
262n/a return self.config.parse_config_files(filenames)
263n/a
264n/a def find_config_files(self):
265n/a return self.config.find_config_files()
266n/a
267n/a # -- Command-line parsing methods ----------------------------------
268n/a
269n/a def parse_command_line(self):
270n/a """Parse the setup script's command line, taken from the
271n/a 'script_args' instance attribute (which defaults to 'sys.argv[1:]'
272n/a -- see 'setup()' in run.py). This list is first processed for
273n/a "global options" -- options that set attributes of the Distribution
274n/a instance. Then, it is alternately scanned for Packaging commands
275n/a and options for that command. Each new command terminates the
276n/a options for the previous command. The allowed options for a
277n/a command are determined by the 'user_options' attribute of the
278n/a command class -- thus, we have to be able to load command classes
279n/a in order to parse the command line. Any error in that 'options'
280n/a attribute raises PackagingGetoptError; any error on the
281n/a command line raises PackagingArgError. If no Packaging commands
282n/a were found on the command line, raises PackagingArgError. Return
283n/a true if command line was successfully parsed and we should carry
284n/a on with executing commands; false if no errors but we shouldn't
285n/a execute commands (currently, this only happens if user asks for
286n/a help).
287n/a """
288n/a #
289n/a # We now have enough information to show the Macintosh dialog
290n/a # that allows the user to interactively specify the "command line".
291n/a #
292n/a toplevel_options = self._get_toplevel_options()
293n/a
294n/a # We have to parse the command line a bit at a time -- global
295n/a # options, then the first command, then its options, and so on --
296n/a # because each command will be handled by a different class, and
297n/a # the options that are valid for a particular class aren't known
298n/a # until we have loaded the command class, which doesn't happen
299n/a # until we know what the command is.
300n/a
301n/a self.commands = []
302n/a parser = FancyGetopt(toplevel_options + self.display_options)
303n/a parser.set_negative_aliases(self.negative_opt)
304n/a args = parser.getopt(args=self.script_args, object=self)
305n/a option_order = parser.get_option_order()
306n/a
307n/a # for display options we return immediately
308n/a if self.handle_display_options(option_order):
309n/a return
310n/a
311n/a while args:
312n/a args = self._parse_command_opts(parser, args)
313n/a if args is None: # user asked for help (and got it)
314n/a return
315n/a
316n/a # Handle the cases of --help as a "global" option, ie.
317n/a # "pysetup run --help" and "pysetup run --help command ...". For the
318n/a # former, we show global options (--dry-run, etc.)
319n/a # and display-only options (--name, --version, etc.); for the
320n/a # latter, we omit the display-only options and show help for
321n/a # each command listed on the command line.
322n/a if self.help:
323n/a self._show_help(parser,
324n/a display_options=len(self.commands) == 0,
325n/a commands=self.commands)
326n/a return
327n/a
328n/a return True
329n/a
330n/a def _get_toplevel_options(self):
331n/a """Return the non-display options recognized at the top level.
332n/a
333n/a This includes options that are recognized *only* at the top
334n/a level as well as options recognized for commands.
335n/a """
336n/a return self.global_options
337n/a
338n/a def _parse_command_opts(self, parser, args):
339n/a """Parse the command-line options for a single command.
340n/a 'parser' must be a FancyGetopt instance; 'args' must be the list
341n/a of arguments, starting with the current command (whose options
342n/a we are about to parse). Returns a new version of 'args' with
343n/a the next command at the front of the list; will be the empty
344n/a list if there are no more commands on the command line. Returns
345n/a None if the user asked for help on this command.
346n/a """
347n/a # Pull the current command from the head of the command line
348n/a command = args[0]
349n/a if not command_re.match(command):
350n/a raise SystemExit("invalid command name %r" % command)
351n/a self.commands.append(command)
352n/a
353n/a # Dig up the command class that implements this command, so we
354n/a # 1) know that it's a valid command, and 2) know which options
355n/a # it takes.
356n/a try:
357n/a cmd_class = get_command_class(command)
358n/a except PackagingModuleError as msg:
359n/a raise PackagingArgError(msg)
360n/a
361n/a # XXX We want to push this in packaging.command
362n/a #
363n/a # Require that the command class be derived from Command -- want
364n/a # to be sure that the basic "command" interface is implemented.
365n/a for meth in ('initialize_options', 'finalize_options', 'run'):
366n/a if hasattr(cmd_class, meth):
367n/a continue
368n/a raise PackagingClassError(
369n/a 'command %r must implement %r' % (cmd_class, meth))
370n/a
371n/a # Also make sure that the command object provides a list of its
372n/a # known options.
373n/a if not (hasattr(cmd_class, 'user_options') and
374n/a isinstance(cmd_class.user_options, list)):
375n/a raise PackagingClassError(
376n/a "command class %s must provide "
377n/a "'user_options' attribute (a list of tuples)" % cmd_class)
378n/a
379n/a # If the command class has a list of negative alias options,
380n/a # merge it in with the global negative aliases.
381n/a negative_opt = self.negative_opt
382n/a if hasattr(cmd_class, 'negative_opt'):
383n/a negative_opt = negative_opt.copy()
384n/a negative_opt.update(cmd_class.negative_opt)
385n/a
386n/a # Check for help_options in command class. They have a different
387n/a # format (tuple of four) so we need to preprocess them here.
388n/a if (hasattr(cmd_class, 'help_options') and
389n/a isinstance(cmd_class.help_options, list)):
390n/a help_options = cmd_class.help_options[:]
391n/a else:
392n/a help_options = []
393n/a
394n/a # All commands support the global options too, just by adding
395n/a # in 'global_options'.
396n/a parser.set_option_table(self.global_options +
397n/a cmd_class.user_options +
398n/a help_options)
399n/a parser.set_negative_aliases(negative_opt)
400n/a args, opts = parser.getopt(args[1:])
401n/a if hasattr(opts, 'help') and opts.help:
402n/a self._show_help(parser, display_options=False,
403n/a commands=[cmd_class])
404n/a return
405n/a
406n/a if (hasattr(cmd_class, 'help_options') and
407n/a isinstance(cmd_class.help_options, list)):
408n/a help_option_found = False
409n/a for help_option, short, desc, func in cmd_class.help_options:
410n/a if hasattr(opts, help_option.replace('-', '_')):
411n/a help_option_found = True
412n/a if callable(func):
413n/a func()
414n/a else:
415n/a raise PackagingClassError(
416n/a "invalid help function %r for help option %r: "
417n/a "must be a callable object (function, etc.)"
418n/a % (func, help_option))
419n/a
420n/a if help_option_found:
421n/a return
422n/a
423n/a # Put the options from the command line into their official
424n/a # holding pen, the 'command_options' dictionary.
425n/a opt_dict = self.get_option_dict(command)
426n/a for name, value in vars(opts).items():
427n/a opt_dict[name] = ("command line", value)
428n/a
429n/a return args
430n/a
431n/a def finalize_options(self):
432n/a """Set final values for all the options on the Distribution
433n/a instance, analogous to the .finalize_options() method of Command
434n/a objects.
435n/a """
436n/a if getattr(self, 'convert_2to3_doctests', None):
437n/a self.convert_2to3_doctests = [os.path.join(p)
438n/a for p in self.convert_2to3_doctests]
439n/a else:
440n/a self.convert_2to3_doctests = []
441n/a
442n/a def _show_help(self, parser, global_options=True, display_options=True,
443n/a commands=[]):
444n/a """Show help for the setup script command line in the form of
445n/a several lists of command-line options. 'parser' should be a
446n/a FancyGetopt instance; do not expect it to be returned in the
447n/a same state, as its option table will be reset to make it
448n/a generate the correct help text.
449n/a
450n/a If 'global_options' is true, lists the global options:
451n/a --dry-run, etc. If 'display_options' is true, lists
452n/a the "display-only" options: --help-commands. Finally,
453n/a lists per-command help for every command name or command class
454n/a in 'commands'.
455n/a """
456n/a if global_options:
457n/a if display_options:
458n/a options = self._get_toplevel_options()
459n/a else:
460n/a options = self.global_options
461n/a parser.set_option_table(options)
462n/a parser.print_help(self.common_usage + "\nGlobal options:")
463n/a print()
464n/a
465n/a if display_options:
466n/a parser.set_option_table(self.display_options)
467n/a parser.print_help(
468n/a "Information display options (just display " +
469n/a "information, ignore any commands)")
470n/a print()
471n/a
472n/a for command in self.commands:
473n/a if isinstance(command, type) and issubclass(command, Command):
474n/a cls = command
475n/a else:
476n/a cls = get_command_class(command)
477n/a if (hasattr(cls, 'help_options') and
478n/a isinstance(cls.help_options, list)):
479n/a parser.set_option_table(cls.user_options + cls.help_options)
480n/a else:
481n/a parser.set_option_table(cls.user_options)
482n/a parser.print_help("Options for %r command:" % cls.__name__)
483n/a print()
484n/a
485n/a print(gen_usage(self.script_name))
486n/a
487n/a def handle_display_options(self, option_order):
488n/a """If there were any non-global "display-only" options
489n/a (--help-commands) on the command line, display the requested info and
490n/a return true; else return false.
491n/a """
492n/a # User just wants a list of commands -- we'll print it out and stop
493n/a # processing now (ie. if they ran "setup --help-commands foo bar",
494n/a # we ignore "foo bar").
495n/a if self.help_commands:
496n/a self.print_commands()
497n/a print()
498n/a print(gen_usage(self.script_name))
499n/a return True
500n/a
501n/a # If user supplied any of the "display metadata" options, then
502n/a # display that metadata in the order in which the user supplied the
503n/a # metadata options.
504n/a any_display_options = False
505n/a is_display_option = set()
506n/a for option in self.display_options:
507n/a is_display_option.add(option[0])
508n/a
509n/a for opt, val in option_order:
510n/a if val and opt in is_display_option:
511n/a opt = opt.replace('-', '_')
512n/a value = self.metadata[opt]
513n/a if opt in ('keywords', 'platform'):
514n/a print(','.join(value))
515n/a elif opt in ('classifier', 'provides', 'requires',
516n/a 'obsoletes'):
517n/a print('\n'.join(value))
518n/a else:
519n/a print(value)
520n/a any_display_options = True
521n/a
522n/a return any_display_options
523n/a
524n/a def print_command_list(self, commands, header, max_length):
525n/a """Print a subset of the list of all commands -- used by
526n/a 'print_commands()'.
527n/a """
528n/a print(header + ":")
529n/a
530n/a for cmd in commands:
531n/a cls = self.cmdclass.get(cmd) or get_command_class(cmd)
532n/a description = getattr(cls, 'description',
533n/a '(no description available)')
534n/a
535n/a print(" %-*s %s" % (max_length, cmd, description))
536n/a
537n/a def _get_command_groups(self):
538n/a """Helper function to retrieve all the command class names divided
539n/a into standard commands (listed in
540n/a packaging.command.STANDARD_COMMANDS) and extra commands (given in
541n/a self.cmdclass and not standard commands).
542n/a """
543n/a extra_commands = [cmd for cmd in self.cmdclass
544n/a if cmd not in STANDARD_COMMANDS]
545n/a return STANDARD_COMMANDS, extra_commands
546n/a
547n/a def print_commands(self):
548n/a """Print out a help message listing all available commands with a
549n/a description of each. The list is divided into standard commands
550n/a (listed in packaging.command.STANDARD_COMMANDS) and extra commands
551n/a (given in self.cmdclass and not standard commands). The
552n/a descriptions come from the command class attribute
553n/a 'description'.
554n/a """
555n/a std_commands, extra_commands = self._get_command_groups()
556n/a max_length = 0
557n/a for cmd in (std_commands + extra_commands):
558n/a if len(cmd) > max_length:
559n/a max_length = len(cmd)
560n/a
561n/a self.print_command_list(std_commands,
562n/a "Standard commands",
563n/a max_length)
564n/a if extra_commands:
565n/a print()
566n/a self.print_command_list(extra_commands,
567n/a "Extra commands",
568n/a max_length)
569n/a
570n/a # -- Command class/object methods ----------------------------------
571n/a
572n/a def get_command_obj(self, command, create=True):
573n/a """Return the command object for 'command'. Normally this object
574n/a is cached on a previous call to 'get_command_obj()'; if no command
575n/a object for 'command' is in the cache, then we either create and
576n/a return it (if 'create' is true) or return None.
577n/a """
578n/a cmd_obj = self.command_obj.get(command)
579n/a if not cmd_obj and create:
580n/a logger.debug("Distribution.get_command_obj(): "
581n/a "creating %r command object", command)
582n/a
583n/a cls = get_command_class(command)
584n/a cmd_obj = self.command_obj[command] = cls(self)
585n/a self.have_run[command] = 0
586n/a
587n/a # Set any options that were supplied in config files or on the
588n/a # command line. (XXX support for error reporting is suboptimal
589n/a # here: errors aren't reported until finalize_options is called,
590n/a # which means we won't report the source of the error.)
591n/a options = self.command_options.get(command)
592n/a if options:
593n/a self._set_command_options(cmd_obj, options)
594n/a
595n/a return cmd_obj
596n/a
597n/a def _set_command_options(self, command_obj, option_dict=None):
598n/a """Set the options for 'command_obj' from 'option_dict'. Basically
599n/a this means copying elements of a dictionary ('option_dict') to
600n/a attributes of an instance ('command').
601n/a
602n/a 'command_obj' must be a Command instance. If 'option_dict' is not
603n/a supplied, uses the standard option dictionary for this command
604n/a (from 'self.command_options').
605n/a """
606n/a command_name = command_obj.get_command_name()
607n/a if option_dict is None:
608n/a option_dict = self.get_option_dict(command_name)
609n/a
610n/a logger.debug(" setting options for %r command:", command_name)
611n/a
612n/a for option, (source, value) in option_dict.items():
613n/a logger.debug(" %s = %s (from %s)", option, value, source)
614n/a try:
615n/a bool_opts = [x.replace('-', '_')
616n/a for x in command_obj.boolean_options]
617n/a except AttributeError:
618n/a bool_opts = []
619n/a try:
620n/a neg_opt = command_obj.negative_opt
621n/a except AttributeError:
622n/a neg_opt = {}
623n/a
624n/a try:
625n/a is_string = isinstance(value, str)
626n/a if option in neg_opt and is_string:
627n/a setattr(command_obj, neg_opt[option], not strtobool(value))
628n/a elif option in bool_opts and is_string:
629n/a setattr(command_obj, option, strtobool(value))
630n/a elif hasattr(command_obj, option):
631n/a setattr(command_obj, option, value)
632n/a else:
633n/a raise PackagingOptionError(
634n/a "error in %s: command %r has no such option %r" %
635n/a (source, command_name, option))
636n/a except ValueError as msg:
637n/a raise PackagingOptionError(msg)
638n/a
639n/a def reinitialize_command(self, command, reinit_subcommands=False):
640n/a """Reinitializes a command to the state it was in when first
641n/a returned by 'get_command_obj()': i.e., initialized but not yet
642n/a finalized. This provides the opportunity to sneak option
643n/a values in programmatically, overriding or supplementing
644n/a user-supplied values from the config files and command line.
645n/a You'll have to re-finalize the command object (by calling
646n/a 'finalize_options()' or 'ensure_finalized()') before using it for
647n/a real.
648n/a
649n/a 'command' should be a command name (string) or command object. If
650n/a 'reinit_subcommands' is true, also reinitializes the command's
651n/a sub-commands, as declared by the 'sub_commands' class attribute (if
652n/a it has one). See the "install_dist" command for an example. Only
653n/a reinitializes the sub-commands that actually matter, i.e. those
654n/a whose test predicate return true.
655n/a
656n/a Returns the reinitialized command object. It will be the same
657n/a object as the one stored in the self.command_obj attribute.
658n/a """
659n/a if not isinstance(command, Command):
660n/a command_name = command
661n/a command = self.get_command_obj(command_name)
662n/a else:
663n/a command_name = command.get_command_name()
664n/a
665n/a if not command.finalized:
666n/a return command
667n/a
668n/a command.initialize_options()
669n/a self.have_run[command_name] = 0
670n/a command.finalized = False
671n/a self._set_command_options(command)
672n/a
673n/a if reinit_subcommands:
674n/a for sub in command.get_sub_commands():
675n/a self.reinitialize_command(sub, reinit_subcommands)
676n/a
677n/a return command
678n/a
679n/a # -- Methods that operate on the Distribution ----------------------
680n/a
681n/a def run_commands(self):
682n/a """Run each command that was seen on the setup script command line.
683n/a Uses the list of commands found and cache of command objects
684n/a created by 'get_command_obj()'.
685n/a """
686n/a for cmd in self.commands:
687n/a self.run_command(cmd)
688n/a
689n/a # -- Methods that operate on its Commands --------------------------
690n/a
691n/a def run_command(self, command, options=None):
692n/a """Do whatever it takes to run a command (including nothing at all,
693n/a if the command has already been run). Specifically: if we have
694n/a already created and run the command named by 'command', return
695n/a silently without doing anything. If the command named by 'command'
696n/a doesn't even have a command object yet, create one. Then invoke
697n/a 'run()' on that command object (or an existing one).
698n/a """
699n/a # Already been here, done that? then return silently.
700n/a if self.have_run.get(command):
701n/a return
702n/a
703n/a if options is not None:
704n/a self.command_options[command] = options
705n/a
706n/a cmd_obj = self.get_command_obj(command)
707n/a cmd_obj.ensure_finalized()
708n/a self.run_command_hooks(cmd_obj, 'pre_hook')
709n/a logger.info("running %s", command)
710n/a cmd_obj.run()
711n/a self.run_command_hooks(cmd_obj, 'post_hook')
712n/a self.have_run[command] = 1
713n/a
714n/a def run_command_hooks(self, cmd_obj, hook_kind):
715n/a """Run hooks registered for that command and phase.
716n/a
717n/a *cmd_obj* is a finalized command object; *hook_kind* is either
718n/a 'pre_hook' or 'post_hook'.
719n/a """
720n/a if hook_kind not in ('pre_hook', 'post_hook'):
721n/a raise ValueError('invalid hook kind: %r' % hook_kind)
722n/a
723n/a hooks = getattr(cmd_obj, hook_kind, None)
724n/a
725n/a if hooks is None:
726n/a return
727n/a
728n/a for hook in hooks.values():
729n/a if isinstance(hook, str):
730n/a try:
731n/a hook_obj = resolve_name(hook)
732n/a except ImportError as e:
733n/a raise PackagingModuleError(e)
734n/a else:
735n/a hook_obj = hook
736n/a
737n/a if not callable(hook_obj):
738n/a raise PackagingOptionError('hook %r is not callable' % hook)
739n/a
740n/a logger.info('running %s %s for command %s',
741n/a hook_kind, hook, cmd_obj.get_command_name())
742n/a hook_obj(cmd_obj)
743n/a
744n/a # -- Distribution query methods ------------------------------------
745n/a def has_pure_modules(self):
746n/a return len(self.packages or self.py_modules or []) > 0
747n/a
748n/a def has_ext_modules(self):
749n/a return self.ext_modules and len(self.ext_modules) > 0
750n/a
751n/a def has_c_libraries(self):
752n/a return self.libraries and len(self.libraries) > 0
753n/a
754n/a def has_modules(self):
755n/a return self.has_pure_modules() or self.has_ext_modules()
756n/a
757n/a def has_headers(self):
758n/a return self.headers and len(self.headers) > 0
759n/a
760n/a def has_scripts(self):
761n/a return self.scripts and len(self.scripts) > 0
762n/a
763n/a def has_data_files(self):
764n/a return self.data_files and len(self.data_files) > 0
765n/a
766n/a def is_pure(self):
767n/a return (self.has_pure_modules() and
768n/a not self.has_ext_modules() and
769n/a not self.has_c_libraries())