]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/setuptools/_distutils/dist.py
3 Provides the Distribution class, which represents the module distribution
4 being built/installed/distributed.
13 from email
import message_from_file
26 from .fancy_getopt
import FancyGetopt
, translate_longopt
27 from .util
import check_environ
, strtobool
, rfc822_escape
29 from .debug
import DEBUG
31 # Regex to define acceptable Distutils command names. This is not *quite*
32 # the same as a Python NAME -- I don't allow leading underscores. The fact
33 # that they're very similar is no coincidence; the default naming scheme is
34 # to look for a Python module named after the command.
35 command_re
= re
.compile(r
'^[a-zA-Z]([a-zA-Z0-9_]*)$')
38 def _ensure_list(value
, fieldname
):
39 if isinstance(value
, str):
40 # a string containing comma separated values is okay. It will
41 # be converted to a list by Distribution.finalize_options().
43 elif not isinstance(value
, list):
44 # passing a tuple or an iterator perhaps, warn and convert
45 typename
= type(value
).__name
__
46 msg
= "Warning: '{fieldname}' should be a list, got type '{typename}'"
47 msg
= msg
.format(**locals())
54 """The core of the Distutils. Most of the work hiding behind 'setup'
55 is really done within a Distribution instance, which farms the work out
56 to the Distutils commands specified on the command line.
58 Setup scripts will almost never instantiate Distribution directly,
59 unless the 'setup()' function is totally inadequate to their needs.
60 However, it is conceivable that a setup script might wish to subclass
61 Distribution for some specialized purpose, and then pass the subclass
62 to 'setup()' as the 'distclass' keyword argument. If so, it is
63 necessary to respect the expectations that 'setup' has of Distribution.
64 See the code for 'setup()', in core.py, for details.
67 # 'global_options' describes the command-line options that may be
68 # supplied to the setup script prior to any actual commands.
69 # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
70 # these global options. This list should be kept to a bare minimum,
71 # since every global option is also valid as a command option -- and we
72 # don't want to pollute the commands with too many options that they
73 # have minimal control over.
74 # The fourth entry for verbose means that it can be repeated.
76 ('verbose', 'v', "run verbosely (default)", 1),
77 ('quiet', 'q', "run quietly (turns verbosity off)"),
78 ('dry-run', 'n', "don't actually do anything"),
79 ('help', 'h', "show detailed help message"),
80 ('no-user-cfg', None, 'ignore pydistutils.cfg in your home directory'),
83 # 'common_usage' is a short (2-3 line) string describing the common
84 # usage of the setup script.
86 Common commands: (see '--help-commands' for more)
88 setup.py build will build the package underneath 'build/'
89 setup.py install will install the package
92 # options that are not propagated to the commands
94 ('help-commands', None, "list all available commands"),
95 ('name', None, "print package name"),
96 ('version', 'V', "print package version"),
97 ('fullname', None, "print <package name>-<version>"),
98 ('author', None, "print the author's name"),
99 ('author-email', None, "print the author's email address"),
100 ('maintainer', None, "print the maintainer's name"),
101 ('maintainer-email', None, "print the maintainer's email address"),
102 ('contact', None, "print the maintainer's name if known, else the author's"),
106 "print the maintainer's email address if known, else the author's",
108 ('url', None, "print the URL for this package"),
109 ('license', None, "print the license of the package"),
110 ('licence', None, "alias for --license"),
111 ('description', None, "print the package description"),
112 ('long-description', None, "print the long package description"),
113 ('platforms', None, "print the list of platforms"),
114 ('classifiers', None, "print the list of classifiers"),
115 ('keywords', None, "print the list of keywords"),
116 ('provides', None, "print the list of packages/modules provided"),
117 ('requires', None, "print the list of packages/modules required"),
118 ('obsoletes', None, "print the list of packages/modules made obsolete"),
120 display_option_names
= [translate_longopt(x
[0]) for x
in display_options
]
122 # negative options are options that exclude other options
123 negative_opt
= {'quiet': 'verbose'}
125 # -- Creation/initialization methods -------------------------------
127 def __init__(self
, attrs
=None): # noqa: C901
128 """Construct a new Distribution instance: initialize all the
129 attributes of a Distribution, and then use 'attrs' (a dictionary
130 mapping attribute names to values) to assign some of those
131 attributes their "real" values. (Any attributes not mentioned in
132 'attrs' will be assigned to some null value: 0, None, an empty list
133 or dictionary, etc.) Most importantly, initialize the
134 'command_obj' attribute to the empty dictionary; this will be
135 filled in with real command objects by 'parse_command_line()'.
138 # Default values for our command-line options
142 for attr
in self
.display_option_names
:
143 setattr(self
, attr
, 0)
145 # Store the distribution meta-data (name, version, author, and so
146 # forth) in a separate object -- we're getting to have enough
147 # information here (and enough command-line options) that it's
148 # worth it. Also delegate 'get_XXX()' methods to the 'metadata'
149 # object in a sneaky and underhanded (but efficient!) way.
150 self
.metadata
= DistributionMetadata()
151 for basename
in self
.metadata
._METHOD
_BASENAMES
:
152 method_name
= "get_" + basename
153 setattr(self
, method_name
, getattr(self
.metadata
, method_name
))
155 # 'cmdclass' maps command names to class objects, so we
156 # can 1) quickly figure out which class to instantiate when
157 # we need to create a new command object, and 2) have a way
158 # for the setup script to override command classes
161 # 'command_packages' is a list of packages in which commands
162 # are searched for. The factory for command 'foo' is expected
163 # to be named 'foo' in the module 'foo' in one of the packages
164 # named here. This list is searched from the left; an error
165 # is raised if no named package provides the command being
166 # searched for. (Always access using get_command_packages().)
167 self
.command_packages
= None
169 # 'script_name' and 'script_args' are usually set to sys.argv[0]
170 # and sys.argv[1:], but they can be overridden when the caller is
171 # not necessarily a setup script run from the command-line.
172 self
.script_name
= None
173 self
.script_args
= None
175 # 'command_options' is where we store command options between
176 # parsing them (from config files, the command-line, etc.) and when
177 # they are actually needed -- ie. when the command in question is
178 # instantiated. It is a dictionary of dictionaries of 2-tuples:
179 # command_options = { command_name : { option : (source, value) } }
180 self
.command_options
= {}
182 # 'dist_files' is the list of (command, pyversion, file) that
183 # have been created by any dist commands run so far. This is
184 # filled regardless of whether the run is dry or not. pyversion
185 # gives sysconfig.get_python_version() if the dist file is
186 # specific to a Python version, 'any' if it is good for all
187 # Python versions on the target platform, and '' for a source
188 # file. pyversion should not be used to specify minimum or
189 # maximum required Python versions; use the metainfo for that
193 # These options are really the business of various commands, rather
194 # than of the Distribution itself. We provide aliases for them in
195 # Distribution as a convenience to the developer.
197 self
.package_data
= {}
198 self
.package_dir
= None
199 self
.py_modules
= None
200 self
.libraries
= None
202 self
.ext_modules
= None
203 self
.ext_package
= None
204 self
.include_dirs
= None
205 self
.extra_path
= None
207 self
.data_files
= None
210 # And now initialize bookkeeping stuff that can't be supplied by
211 # the caller at all. 'command_obj' maps command names to
212 # Command instances -- that's how we enforce that every command
213 # class is a singleton.
214 self
.command_obj
= {}
216 # 'have_run' maps command names to boolean values; it keeps track
217 # of whether we have actually run a particular command, to make it
218 # cheap to "run" a command whenever we think we might need to -- if
219 # it's already been done, no need for expensive filesystem
220 # operations, we just check the 'have_run' dictionary and carry on.
221 # It's only safe to query 'have_run' for a command class that has
222 # been instantiated -- a false value will be inserted when the
223 # command object is created, and replaced with a true value when
224 # the command is successfully run. Thus it's probably best to use
225 # '.get()' rather than a straight lookup.
228 # Now we'll use the attrs dictionary (ultimately, keyword args from
229 # the setup script) to possibly override any or all of these
230 # distribution options.
233 # Pull out the set of command options and work on them
234 # specifically. Note that this order guarantees that aliased
235 # command options will override any supplied redundantly
236 # through the general options dictionary.
237 options
= attrs
.get('options')
238 if options
is not None:
240 for (command
, cmd_options
) in options
.items():
241 opt_dict
= self
.get_option_dict(command
)
242 for (opt
, val
) in cmd_options
.items():
243 opt_dict
[opt
] = ("setup script", val
)
245 if 'licence' in attrs
:
246 attrs
['license'] = attrs
['licence']
248 msg
= "'licence' distribution option is deprecated; use 'license'"
249 if warnings
is not None:
252 sys
.stderr
.write(msg
+ "\n")
254 # Now work on the rest of the attributes. Any attribute that's
255 # not already defined is invalid!
256 for (key
, val
) in attrs
.items():
257 if hasattr(self
.metadata
, "set_" + key
):
258 getattr(self
.metadata
, "set_" + key
)(val
)
259 elif hasattr(self
.metadata
, key
):
260 setattr(self
.metadata
, key
, val
)
261 elif hasattr(self
, key
):
262 setattr(self
, key
, val
)
264 msg
= "Unknown distribution option: %s" % repr(key
)
267 # no-user-cfg is handled before other command line args
268 # because other args override the config files, and this
269 # one is needed before we can load the config files.
270 # If attrs['script_args'] wasn't passed, assume false.
272 # This also make sure we just look at the global options
273 self
.want_user_cfg
= True
275 if self
.script_args
is not None:
276 for arg
in self
.script_args
:
277 if not arg
.startswith('-'):
279 if arg
== '--no-user-cfg':
280 self
.want_user_cfg
= False
283 self
.finalize_options()
285 def get_option_dict(self
, command
):
286 """Get the option dictionary for a given command. If that
287 command's option dictionary hasn't been created yet, then create it
288 and return the new dictionary; otherwise, return the existing
291 dict = self
.command_options
.get(command
)
293 dict = self
.command_options
[command
] = {}
296 def dump_option_dicts(self
, header
=None, commands
=None, indent
=""):
297 from pprint
import pformat
299 if commands
is None: # dump all command option dicts
300 commands
= sorted(self
.command_options
.keys())
302 if header
is not None:
303 self
.announce(indent
+ header
)
304 indent
= indent
+ " "
307 self
.announce(indent
+ "no commands known yet")
310 for cmd_name
in commands
:
311 opt_dict
= self
.command_options
.get(cmd_name
)
313 self
.announce(indent
+ "no option dict for '%s' command" % cmd_name
)
315 self
.announce(indent
+ "option dict for '%s' command:" % cmd_name
)
316 out
= pformat(opt_dict
)
317 for line
in out
.split('\n'):
318 self
.announce(indent
+ " " + line
)
320 # -- Config file finding/parsing methods ---------------------------
322 def find_config_files(self
):
323 """Find as many configuration files as should be processed for this
324 platform, and return a list of filenames in the order in which they
325 should be parsed. The filenames returned are guaranteed to exist
326 (modulo nasty race conditions).
328 There are multiple possible config files:
329 - distutils.cfg in the Distutils installation directory (i.e.
330 where the top-level Distutils __inst__.py file lives)
331 - a file in the user's home directory named .pydistutils.cfg
332 on Unix and pydistutils.cfg on Windows/Mac; may be disabled
333 with the ``--no-user-cfg`` option
334 - setup.cfg in the current directory
335 - a file named by an environment variable
338 files
= [str(path
) for path
in self
._gen
_paths
() if os
.path
.isfile(path
)]
341 self
.announce("using config files: %s" % ', '.join(files
))
345 def _gen_paths(self
):
346 # The system-wide Distutils config file
347 sys_dir
= pathlib
.Path(sys
.modules
['distutils'].__file
__).parent
348 yield sys_dir
/ "distutils.cfg"
350 # The per-user config file
351 prefix
= '.' * (os
.name
== 'posix')
352 filename
= prefix
+ 'pydistutils.cfg'
353 if self
.want_user_cfg
:
354 yield pathlib
.Path('~').expanduser() / filename
356 # All platforms support local setup.cfg
357 yield pathlib
.Path('setup.cfg')
359 # Additional config indicated in the environment
360 with contextlib
.suppress(TypeError):
361 yield pathlib
.Path(os
.getenv("DIST_EXTRA_CONFIG"))
363 def parse_config_files(self
, filenames
=None): # noqa: C901
364 from configparser
import ConfigParser
366 # Ignore install directory options if we have a venv
367 if sys
.prefix
!= sys
.base_prefix
:
386 ignore_options
= frozenset(ignore_options
)
388 if filenames
is None:
389 filenames
= self
.find_config_files()
392 self
.announce("Distribution.parse_config_files():")
394 parser
= ConfigParser()
395 for filename
in filenames
:
397 self
.announce(" reading %s" % filename
)
398 parser
.read(filename
)
399 for section
in parser
.sections():
400 options
= parser
.options(section
)
401 opt_dict
= self
.get_option_dict(section
)
404 if opt
!= '__name__' and opt
not in ignore_options
:
405 val
= parser
.get(section
, opt
)
406 opt
= opt
.replace('-', '_')
407 opt_dict
[opt
] = (filename
, val
)
409 # Make the ConfigParser forget everything (so we retain
410 # the original filenames that options come from)
413 # If there was a "global" section in the config file, use it
414 # to set Distribution options.
416 if 'global' in self
.command_options
:
417 for (opt
, (src
, val
)) in self
.command_options
['global'].items():
418 alias
= self
.negative_opt
.get(opt
)
421 setattr(self
, alias
, not strtobool(val
))
422 elif opt
in ('verbose', 'dry_run'): # ugh!
423 setattr(self
, opt
, strtobool(val
))
425 setattr(self
, opt
, val
)
426 except ValueError as msg
:
427 raise DistutilsOptionError(msg
)
429 # -- Command-line parsing methods ----------------------------------
431 def parse_command_line(self
):
432 """Parse the setup script's command line, taken from the
433 'script_args' instance attribute (which defaults to 'sys.argv[1:]'
434 -- see 'setup()' in core.py). This list is first processed for
435 "global options" -- options that set attributes of the Distribution
436 instance. Then, it is alternately scanned for Distutils commands
437 and options for that command. Each new command terminates the
438 options for the previous command. The allowed options for a
439 command are determined by the 'user_options' attribute of the
440 command class -- thus, we have to be able to load command classes
441 in order to parse the command line. Any error in that 'options'
442 attribute raises DistutilsGetoptError; any error on the
443 command-line raises DistutilsArgError. If no Distutils commands
444 were found on the command line, raises DistutilsArgError. Return
445 true if command-line was successfully parsed and we should carry
446 on with executing commands; false if no errors but we shouldn't
447 execute commands (currently, this only happens if user asks for
451 # We now have enough information to show the Macintosh dialog
452 # that allows the user to interactively specify the "command line".
454 toplevel_options
= self
._get
_toplevel
_options
()
456 # We have to parse the command line a bit at a time -- global
457 # options, then the first command, then its options, and so on --
458 # because each command will be handled by a different class, and
459 # the options that are valid for a particular class aren't known
460 # until we have loaded the command class, which doesn't happen
461 # until we know what the command is.
464 parser
= FancyGetopt(toplevel_options
+ self
.display_options
)
465 parser
.set_negative_aliases(self
.negative_opt
)
466 parser
.set_aliases({'licence': 'license'})
467 args
= parser
.getopt(args
=self
.script_args
, object=self
)
468 option_order
= parser
.get_option_order()
469 logging
.getLogger().setLevel(logging
.WARN
- 10 * self
.verbose
)
471 # for display options we return immediately
472 if self
.handle_display_options(option_order
):
475 args
= self
._parse
_command
_opts
(parser
, args
)
476 if args
is None: # user asked for help (and got it)
479 # Handle the cases of --help as a "global" option, ie.
480 # "setup.py --help" and "setup.py --help command ...". For the
481 # former, we show global options (--verbose, --dry-run, etc.)
482 # and display-only options (--name, --version, etc.); for the
483 # latter, we omit the display-only options and show help for
484 # each command listed on the command line.
487 parser
, display_options
=len(self
.commands
) == 0, commands
=self
.commands
491 # Oops, no commands found -- an end-user error
492 if not self
.commands
:
493 raise DistutilsArgError("no commands supplied")
495 # All is well: return true
498 def _get_toplevel_options(self
):
499 """Return the non-display options recognized at the top level.
501 This includes options that are recognized *only* at the top
502 level as well as options recognized for commands.
504 return self
.global_options
+ [
508 "list of packages that provide distutils commands",
512 def _parse_command_opts(self
, parser
, args
): # noqa: C901
513 """Parse the command-line options for a single command.
514 'parser' must be a FancyGetopt instance; 'args' must be the list
515 of arguments, starting with the current command (whose options
516 we are about to parse). Returns a new version of 'args' with
517 the next command at the front of the list; will be the empty
518 list if there are no more commands on the command line. Returns
519 None if the user asked for help on this command.
521 # late import because of mutual dependence between these modules
522 from distutils
.cmd
import Command
524 # Pull the current command from the head of the command line
526 if not command_re
.match(command
):
527 raise SystemExit("invalid command name '%s'" % command
)
528 self
.commands
.append(command
)
530 # Dig up the command class that implements this command, so we
531 # 1) know that it's a valid command, and 2) know which options
534 cmd_class
= self
.get_command_class(command
)
535 except DistutilsModuleError
as msg
:
536 raise DistutilsArgError(msg
)
538 # Require that the command class be derived from Command -- want
539 # to be sure that the basic "command" interface is implemented.
540 if not issubclass(cmd_class
, Command
):
541 raise DistutilsClassError(
542 "command class %s must subclass Command" % cmd_class
545 # Also make sure that the command object provides a list of its
548 hasattr(cmd_class
, 'user_options')
549 and isinstance(cmd_class
.user_options
, list)
552 "command class %s must provide "
553 "'user_options' attribute (a list of tuples)"
555 raise DistutilsClassError(msg
% cmd_class
)
557 # If the command class has a list of negative alias options,
558 # merge it in with the global negative aliases.
559 negative_opt
= self
.negative_opt
560 if hasattr(cmd_class
, 'negative_opt'):
561 negative_opt
= negative_opt
.copy()
562 negative_opt
.update(cmd_class
.negative_opt
)
564 # Check for help_options in command class. They have a different
565 # format (tuple of four) so we need to preprocess them here.
566 if hasattr(cmd_class
, 'help_options') and isinstance(
567 cmd_class
.help_options
, list
569 help_options
= fix_help_options(cmd_class
.help_options
)
573 # All commands support the global options too, just by adding
574 # in 'global_options'.
575 parser
.set_option_table(
576 self
.global_options
+ cmd_class
.user_options
+ help_options
578 parser
.set_negative_aliases(negative_opt
)
579 (args
, opts
) = parser
.getopt(args
[1:])
580 if hasattr(opts
, 'help') and opts
.help:
581 self
._show
_help
(parser
, display_options
=0, commands
=[cmd_class
])
584 if hasattr(cmd_class
, 'help_options') and isinstance(
585 cmd_class
.help_options
, list
587 help_option_found
= 0
588 for (help_option
, short
, desc
, func
) in cmd_class
.help_options
:
589 if hasattr(opts
, parser
.get_attr_name(help_option
)):
590 help_option_found
= 1
594 raise DistutilsClassError(
595 "invalid help function %r for help option '%s': "
596 "must be a callable object (function, etc.)"
597 % (func
, help_option
)
600 if help_option_found
:
603 # Put the options from the command-line into their official
604 # holding pen, the 'command_options' dictionary.
605 opt_dict
= self
.get_option_dict(command
)
606 for (name
, value
) in vars(opts
).items():
607 opt_dict
[name
] = ("command line", value
)
611 def finalize_options(self
):
612 """Set final values for all the options on the Distribution
613 instance, analogous to the .finalize_options() method of Command
616 for attr
in ('keywords', 'platforms'):
617 value
= getattr(self
.metadata
, attr
)
620 if isinstance(value
, str):
621 value
= [elm
.strip() for elm
in value
.split(',')]
622 setattr(self
.metadata
, attr
, value
)
624 def _show_help(self
, parser
, global_options
=1, display_options
=1, commands
=[]):
625 """Show help for the setup script command-line in the form of
626 several lists of command-line options. 'parser' should be a
627 FancyGetopt instance; do not expect it to be returned in the
628 same state, as its option table will be reset to make it
629 generate the correct help text.
631 If 'global_options' is true, lists the global options:
632 --verbose, --dry-run, etc. If 'display_options' is true, lists
633 the "display-only" options: --name, --version, etc. Finally,
634 lists per-command help for every command name or command class
637 # late import because of mutual dependence between these modules
638 from distutils
.core
import gen_usage
639 from distutils
.cmd
import Command
643 options
= self
._get
_toplevel
_options
()
645 options
= self
.global_options
646 parser
.set_option_table(options
)
647 parser
.print_help(self
.common_usage
+ "\nGlobal options:")
651 parser
.set_option_table(self
.display_options
)
653 "Information display options (just display "
654 + "information, ignore any commands)"
658 for command
in self
.commands
:
659 if isinstance(command
, type) and issubclass(command
, Command
):
662 klass
= self
.get_command_class(command
)
663 if hasattr(klass
, 'help_options') and isinstance(klass
.help_options
, list):
664 parser
.set_option_table(
665 klass
.user_options
+ fix_help_options(klass
.help_options
)
668 parser
.set_option_table(klass
.user_options
)
669 parser
.print_help("Options for '%s' command:" % klass
.__name
__)
672 print(gen_usage(self
.script_name
))
674 def handle_display_options(self
, option_order
):
675 """If there were any non-global "display-only" options
676 (--help-commands or the metadata display options) on the command
677 line, display the requested info and return true; else return
680 from distutils
.core
import gen_usage
682 # User just wants a list of commands -- we'll print it out and stop
683 # processing now (ie. if they ran "setup --help-commands foo bar",
684 # we ignore "foo bar").
685 if self
.help_commands
:
686 self
.print_commands()
688 print(gen_usage(self
.script_name
))
691 # If user supplied any of the "display metadata" options, then
692 # display that metadata in the order in which the user supplied the
694 any_display_options
= 0
695 is_display_option
= {}
696 for option
in self
.display_options
:
697 is_display_option
[option
[0]] = 1
699 for (opt
, val
) in option_order
:
700 if val
and is_display_option
.get(opt
):
701 opt
= translate_longopt(opt
)
702 value
= getattr(self
.metadata
, "get_" + opt
)()
703 if opt
in ['keywords', 'platforms']:
704 print(','.join(value
))
705 elif opt
in ('classifiers', 'provides', 'requires', 'obsoletes'):
706 print('\n'.join(value
))
709 any_display_options
= 1
711 return any_display_options
713 def print_command_list(self
, commands
, header
, max_length
):
714 """Print a subset of the list of all commands -- used by
720 klass
= self
.cmdclass
.get(cmd
)
722 klass
= self
.get_command_class(cmd
)
724 description
= klass
.description
725 except AttributeError:
726 description
= "(no description available)"
728 print(" %-*s %s" % (max_length
, cmd
, description
))
730 def print_commands(self
):
731 """Print out a help message listing all available commands with a
732 description of each. The list is divided into "standard commands"
733 (listed in distutils.command.__all__) and "extra commands"
734 (mentioned in self.cmdclass, but not a standard command). The
735 descriptions come from the command class attribute
738 import distutils
.command
740 std_commands
= distutils
.command
.__all
__
742 for cmd
in std_commands
:
746 for cmd
in self
.cmdclass
.keys():
747 if not is_std
.get(cmd
):
748 extra_commands
.append(cmd
)
751 for cmd
in std_commands
+ extra_commands
:
752 if len(cmd
) > max_length
:
753 max_length
= len(cmd
)
755 self
.print_command_list(std_commands
, "Standard commands", max_length
)
758 self
.print_command_list(extra_commands
, "Extra commands", max_length
)
760 def get_command_list(self
):
761 """Get a list of (command, description) tuples.
762 The list is divided into "standard commands" (listed in
763 distutils.command.__all__) and "extra commands" (mentioned in
764 self.cmdclass, but not a standard command). The descriptions come
765 from the command class attribute 'description'.
767 # Currently this is only used on Mac OS, for the Mac-only GUI
768 # Distutils interface (by Jack Jansen)
769 import distutils
.command
771 std_commands
= distutils
.command
.__all
__
773 for cmd
in std_commands
:
777 for cmd
in self
.cmdclass
.keys():
778 if not is_std
.get(cmd
):
779 extra_commands
.append(cmd
)
782 for cmd
in std_commands
+ extra_commands
:
783 klass
= self
.cmdclass
.get(cmd
)
785 klass
= self
.get_command_class(cmd
)
787 description
= klass
.description
788 except AttributeError:
789 description
= "(no description available)"
790 rv
.append((cmd
, description
))
793 # -- Command class/object methods ----------------------------------
795 def get_command_packages(self
):
796 """Return a list of packages from which commands are loaded."""
797 pkgs
= self
.command_packages
798 if not isinstance(pkgs
, list):
801 pkgs
= [pkg
.strip() for pkg
in pkgs
.split(',') if pkg
!= '']
802 if "distutils.command" not in pkgs
:
803 pkgs
.insert(0, "distutils.command")
804 self
.command_packages
= pkgs
807 def get_command_class(self
, command
):
808 """Return the class that implements the Distutils command named by
809 'command'. First we check the 'cmdclass' dictionary; if the
810 command is mentioned there, we fetch the class object from the
811 dictionary and return it. Otherwise we load the command module
812 ("distutils.command." + command) and fetch the command class from
813 the module. The loaded class is also stored in 'cmdclass'
814 to speed future calls to 'get_command_class()'.
816 Raises DistutilsModuleError if the expected module could not be
817 found, or if that module does not define the expected class.
819 klass
= self
.cmdclass
.get(command
)
823 for pkgname
in self
.get_command_packages():
824 module_name
= "{}.{}".format(pkgname
, command
)
828 __import__(module_name
)
829 module
= sys
.modules
[module_name
]
834 klass
= getattr(module
, klass_name
)
835 except AttributeError:
836 raise DistutilsModuleError(
837 "invalid command '%s' (no class '%s' in module '%s')"
838 % (command
, klass_name
, module_name
)
841 self
.cmdclass
[command
] = klass
844 raise DistutilsModuleError("invalid command '%s'" % command
)
846 def get_command_obj(self
, command
, create
=1):
847 """Return the command object for 'command'. Normally this object
848 is cached on a previous call to 'get_command_obj()'; if no command
849 object for 'command' is in the cache, then we either create and
850 return it (if 'create' is true) or return None.
852 cmd_obj
= self
.command_obj
.get(command
)
853 if not cmd_obj
and create
:
856 "Distribution.get_command_obj(): "
857 "creating '%s' command object" % command
860 klass
= self
.get_command_class(command
)
861 cmd_obj
= self
.command_obj
[command
] = klass(self
)
862 self
.have_run
[command
] = 0
864 # Set any options that were supplied in config files
865 # or on the command line. (NB. support for error
866 # reporting is lame here: any errors aren't reported
867 # until 'finalize_options()' is called, which means
868 # we won't report the source of the error.)
869 options
= self
.command_options
.get(command
)
871 self
._set
_command
_options
(cmd_obj
, options
)
875 def _set_command_options(self
, command_obj
, option_dict
=None): # noqa: C901
876 """Set the options for 'command_obj' from 'option_dict'. Basically
877 this means copying elements of a dictionary ('option_dict') to
878 attributes of an instance ('command').
880 'command_obj' must be a Command instance. If 'option_dict' is not
881 supplied, uses the standard option dictionary for this command
882 (from 'self.command_options').
884 command_name
= command_obj
.get_command_name()
885 if option_dict
is None:
886 option_dict
= self
.get_option_dict(command_name
)
889 self
.announce(" setting options for '%s' command:" % command_name
)
890 for (option
, (source
, value
)) in option_dict
.items():
892 self
.announce(" {} = {} (from {})".format(option
, value
, source
))
894 bool_opts
= [translate_longopt(o
) for o
in command_obj
.boolean_options
]
895 except AttributeError:
898 neg_opt
= command_obj
.negative_opt
899 except AttributeError:
903 is_string
= isinstance(value
, str)
904 if option
in neg_opt
and is_string
:
905 setattr(command_obj
, neg_opt
[option
], not strtobool(value
))
906 elif option
in bool_opts
and is_string
:
907 setattr(command_obj
, option
, strtobool(value
))
908 elif hasattr(command_obj
, option
):
909 setattr(command_obj
, option
, value
)
911 raise DistutilsOptionError(
912 "error in %s: command '%s' has no such option '%s'"
913 % (source
, command_name
, option
)
915 except ValueError as msg
:
916 raise DistutilsOptionError(msg
)
918 def reinitialize_command(self
, command
, reinit_subcommands
=0):
919 """Reinitializes a command to the state it was in when first
920 returned by 'get_command_obj()': ie., initialized but not yet
921 finalized. This provides the opportunity to sneak option
922 values in programmatically, overriding or supplementing
923 user-supplied values from the config files and command line.
924 You'll have to re-finalize the command object (by calling
925 'finalize_options()' or 'ensure_finalized()') before using it for
928 'command' should be a command name (string) or command object. If
929 'reinit_subcommands' is true, also reinitializes the command's
930 sub-commands, as declared by the 'sub_commands' class attribute (if
931 it has one). See the "install" command for an example. Only
932 reinitializes the sub-commands that actually matter, ie. those
933 whose test predicates return true.
935 Returns the reinitialized command object.
937 from distutils
.cmd
import Command
939 if not isinstance(command
, Command
):
940 command_name
= command
941 command
= self
.get_command_obj(command_name
)
943 command_name
= command
.get_command_name()
945 if not command
.finalized
:
947 command
.initialize_options()
948 command
.finalized
= 0
949 self
.have_run
[command_name
] = 0
950 self
._set
_command
_options
(command
)
952 if reinit_subcommands
:
953 for sub
in command
.get_sub_commands():
954 self
.reinitialize_command(sub
, reinit_subcommands
)
958 # -- Methods that operate on the Distribution ----------------------
960 def announce(self
, msg
, level
=logging
.INFO
):
963 def run_commands(self
):
964 """Run each command that was seen on the setup script command line.
965 Uses the list of commands found and cache of command objects
966 created by 'get_command_obj()'.
968 for cmd
in self
.commands
:
969 self
.run_command(cmd
)
971 # -- Methods that operate on its Commands --------------------------
973 def run_command(self
, command
):
974 """Do whatever it takes to run a command (including nothing at all,
975 if the command has already been run). Specifically: if we have
976 already created and run the command named by 'command', return
977 silently without doing anything. If the command named by 'command'
978 doesn't even have a command object yet, create one. Then invoke
979 'run()' on that command object (or an existing one).
981 # Already been here, done that? then return silently.
982 if self
.have_run
.get(command
):
985 log
.info("running %s", command
)
986 cmd_obj
= self
.get_command_obj(command
)
987 cmd_obj
.ensure_finalized()
989 self
.have_run
[command
] = 1
991 # -- Distribution query methods ------------------------------------
993 def has_pure_modules(self
):
994 return len(self
.packages
or self
.py_modules
or []) > 0
996 def has_ext_modules(self
):
997 return self
.ext_modules
and len(self
.ext_modules
) > 0
999 def has_c_libraries(self
):
1000 return self
.libraries
and len(self
.libraries
) > 0
1002 def has_modules(self
):
1003 return self
.has_pure_modules() or self
.has_ext_modules()
1005 def has_headers(self
):
1006 return self
.headers
and len(self
.headers
) > 0
1008 def has_scripts(self
):
1009 return self
.scripts
and len(self
.scripts
) > 0
1011 def has_data_files(self
):
1012 return self
.data_files
and len(self
.data_files
) > 0
1016 self
.has_pure_modules()
1017 and not self
.has_ext_modules()
1018 and not self
.has_c_libraries()
1021 # -- Metadata query methods ----------------------------------------
1023 # If you're looking for 'get_name()', 'get_version()', and so forth,
1024 # they are defined in a sneaky way: the constructor binds self.get_XXX
1025 # to self.metadata.get_XXX. The actual code is in the
1026 # DistributionMetadata class, below.
1029 class DistributionMetadata
:
1030 """Dummy class to hold the distribution meta-data: name, version,
1031 author, and so forth.
1034 _METHOD_BASENAMES
= (
1058 def __init__(self
, path
=None):
1059 if path
is not None:
1060 self
.read_pkg_file(open(path
))
1065 self
.author_email
= None
1066 self
.maintainer
= None
1067 self
.maintainer_email
= None
1070 self
.description
= None
1071 self
.long_description
= None
1072 self
.keywords
= None
1073 self
.platforms
= None
1074 self
.classifiers
= None
1075 self
.download_url
= None
1077 self
.provides
= None
1078 self
.requires
= None
1079 self
.obsoletes
= None
1081 def read_pkg_file(self
, file):
1082 """Reads the metadata values from a file object."""
1083 msg
= message_from_file(file)
1085 def _read_field(name
):
1087 if value
and value
!= "UNKNOWN":
1090 def _read_list(name
):
1091 values
= msg
.get_all(name
, None)
1096 metadata_version
= msg
['metadata-version']
1097 self
.name
= _read_field('name')
1098 self
.version
= _read_field('version')
1099 self
.description
= _read_field('summary')
1100 # we are filling author only.
1101 self
.author
= _read_field('author')
1102 self
.maintainer
= None
1103 self
.author_email
= _read_field('author-email')
1104 self
.maintainer_email
= None
1105 self
.url
= _read_field('home-page')
1106 self
.license
= _read_field('license')
1108 if 'download-url' in msg
:
1109 self
.download_url
= _read_field('download-url')
1111 self
.download_url
= None
1113 self
.long_description
= _read_field('description')
1114 self
.description
= _read_field('summary')
1116 if 'keywords' in msg
:
1117 self
.keywords
= _read_field('keywords').split(',')
1119 self
.platforms
= _read_list('platform')
1120 self
.classifiers
= _read_list('classifier')
1122 # PEP 314 - these fields only exist in 1.1
1123 if metadata_version
== '1.1':
1124 self
.requires
= _read_list('requires')
1125 self
.provides
= _read_list('provides')
1126 self
.obsoletes
= _read_list('obsoletes')
1128 self
.requires
= None
1129 self
.provides
= None
1130 self
.obsoletes
= None
1132 def write_pkg_info(self
, base_dir
):
1133 """Write the PKG-INFO file into the release tree."""
1135 os
.path
.join(base_dir
, 'PKG-INFO'), 'w', encoding
='UTF-8'
1137 self
.write_pkg_file(pkg_info
)
1139 def write_pkg_file(self
, file):
1140 """Write the PKG-INFO format data to a file object."""
1147 or self
.download_url
1152 file.write('Metadata-Version: %s\n' % version
)
1153 file.write('Name: %s\n' % self
.get_name())
1154 file.write('Version: %s\n' % self
.get_version())
1156 def maybe_write(header
, val
):
1158 file.write(f
"{header}: {val}\n")
1161 maybe_write("Summary", self
.get_description())
1162 maybe_write("Home-page", self
.get_url())
1163 maybe_write("Author", self
.get_contact())
1164 maybe_write("Author-email", self
.get_contact_email())
1165 maybe_write("License", self
.get_license())
1166 maybe_write("Download-URL", self
.download_url
)
1167 maybe_write("Description", rfc822_escape(self
.get_long_description() or ""))
1168 maybe_write("Keywords", ",".join(self
.get_keywords()))
1170 self
._write
_list
(file, 'Platform', self
.get_platforms())
1171 self
._write
_list
(file, 'Classifier', self
.get_classifiers())
1174 self
._write
_list
(file, 'Requires', self
.get_requires())
1175 self
._write
_list
(file, 'Provides', self
.get_provides())
1176 self
._write
_list
(file, 'Obsoletes', self
.get_obsoletes())
1178 def _write_list(self
, file, name
, values
):
1179 values
= values
or []
1180 for value
in values
:
1181 file.write('{}: {}\n'.format(name
, value
))
1183 # -- Metadata query methods ----------------------------------------
1186 return self
.name
or "UNKNOWN"
1188 def get_version(self
):
1189 return self
.version
or "0.0.0"
1191 def get_fullname(self
):
1192 return "{}-{}".format(self
.get_name(), self
.get_version())
1194 def get_author(self
):
1197 def get_author_email(self
):
1198 return self
.author_email
1200 def get_maintainer(self
):
1201 return self
.maintainer
1203 def get_maintainer_email(self
):
1204 return self
.maintainer_email
1206 def get_contact(self
):
1207 return self
.maintainer
or self
.author
1209 def get_contact_email(self
):
1210 return self
.maintainer_email
or self
.author_email
1215 def get_license(self
):
1218 get_licence
= get_license
1220 def get_description(self
):
1221 return self
.description
1223 def get_long_description(self
):
1224 return self
.long_description
1226 def get_keywords(self
):
1227 return self
.keywords
or []
1229 def set_keywords(self
, value
):
1230 self
.keywords
= _ensure_list(value
, 'keywords')
1232 def get_platforms(self
):
1233 return self
.platforms
1235 def set_platforms(self
, value
):
1236 self
.platforms
= _ensure_list(value
, 'platforms')
1238 def get_classifiers(self
):
1239 return self
.classifiers
or []
1241 def set_classifiers(self
, value
):
1242 self
.classifiers
= _ensure_list(value
, 'classifiers')
1244 def get_download_url(self
):
1245 return self
.download_url
1248 def get_requires(self
):
1249 return self
.requires
or []
1251 def set_requires(self
, value
):
1252 import distutils
.versionpredicate
1255 distutils
.versionpredicate
.VersionPredicate(v
)
1256 self
.requires
= list(value
)
1258 def get_provides(self
):
1259 return self
.provides
or []
1261 def set_provides(self
, value
):
1262 value
= [v
.strip() for v
in value
]
1264 import distutils
.versionpredicate
1266 distutils
.versionpredicate
.split_provision(v
)
1267 self
.provides
= value
1269 def get_obsoletes(self
):
1270 return self
.obsoletes
or []
1272 def set_obsoletes(self
, value
):
1273 import distutils
.versionpredicate
1276 distutils
.versionpredicate
.VersionPredicate(v
)
1277 self
.obsoletes
= list(value
)
1280 def fix_help_options(options
):
1281 """Convert a 4-tuple 'help_options' list as found in various command
1282 classes to the 3-tuple form required by FancyGetopt.
1285 for help_tuple
in options
:
1286 new_options
.append(help_tuple
[0:3])