blob: 24c8d2b85348869070fd4c689f6fac31c5c02b5f [file] [log] [blame]
Greg Wardfe6462c2000-04-04 01:40:52 +00001"""distutils.dist
2
3Provides the Distribution class, which represents the module distribution
4being built/installed/distributed."""
5
6# created 2000/04/03, Greg Ward
7# (extricated from core.py; actually dates back to the beginning)
8
9__revision__ = "$Id$"
10
Gregory P. Smith14263542000-05-12 00:41:33 +000011import sys, os, string, re
Greg Wardfe6462c2000-04-04 01:40:52 +000012from types import *
13from copy import copy
14from distutils.errors import *
Greg Ward82715e12000-04-21 02:28:14 +000015from distutils.fancy_getopt import FancyGetopt, longopt_xlate
Gregory P. Smith14263542000-05-12 00:41:33 +000016from distutils.util import check_environ
Greg Wardfe6462c2000-04-04 01:40:52 +000017
18
19# Regex to define acceptable Distutils command names. This is not *quite*
20# the same as a Python NAME -- I don't allow leading underscores. The fact
21# that they're very similar is no coincidence; the default naming scheme is
22# to look for a Python module named after the command.
23command_re = re.compile (r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
24
25
26class Distribution:
27 """The core of the Distutils. Most of the work hiding behind
28 'setup' is really done within a Distribution instance, which
29 farms the work out to the Distutils commands specified on the
30 command line.
31
32 Clients will almost never instantiate Distribution directly,
33 unless the 'setup' function is totally inadequate to their needs.
34 However, it is conceivable that a client might wish to subclass
35 Distribution for some specialized purpose, and then pass the
36 subclass to 'setup' as the 'distclass' keyword argument. If so,
37 it is necessary to respect the expectations that 'setup' has of
38 Distribution: it must have a constructor and methods
39 'parse_command_line()' and 'run_commands()' with signatures like
40 those described below."""
41
42
43 # 'global_options' describes the command-line options that may be
Greg Ward82715e12000-04-21 02:28:14 +000044 # supplied to the setup script prior to any actual commands.
45 # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of
Greg Wardfe6462c2000-04-04 01:40:52 +000046 # these global options. This list should be kept to a bare minimum,
47 # since every global option is also valid as a command option -- and we
48 # don't want to pollute the commands with too many options that they
49 # have minimal control over.
50 global_options = [('verbose', 'v',
51 "run verbosely (default)"),
52 ('quiet', 'q',
53 "run quietly (turns verbosity off)"),
54 ('dry-run', 'n',
55 "don't actually do anything"),
Greg Wardfe6462c2000-04-04 01:40:52 +000056 ('help', 'h',
Greg Ward82715e12000-04-21 02:28:14 +000057 "show this help message, plus help for any commands " +
58 "given on the command-line"),
Greg Wardfe6462c2000-04-04 01:40:52 +000059 ]
Greg Ward82715e12000-04-21 02:28:14 +000060
61 # options that are not propagated to the commands
62 display_options = [
63 ('help-commands', None,
64 "list all available commands"),
65 ('name', None,
66 "print package name"),
67 ('version', 'V',
68 "print package version"),
69 ('fullname', None,
70 "print <package name>-<version>"),
71 ('author', None,
72 "print the author's name"),
73 ('author-email', None,
74 "print the author's email address"),
75 ('maintainer', None,
76 "print the maintainer's name"),
77 ('maintainer-email', None,
78 "print the maintainer's email address"),
79 ('contact', None,
80 "print the name of the maintainer if present, "
81 "else author"),
82 ('contact-email', None,
83 "print the email of the maintainer if present, "
84 "else author"),
85 ('url', None,
86 "print the URL for this package"),
87 ('licence', None,
88 "print the licence of the package"),
89 ('license', None,
90 "alias for --licence"),
91 ('description', None,
92 "print the package description"),
Greg Warde5a584e2000-04-26 02:26:55 +000093 ('long-description', None,
94 "print the long package description"),
Greg Ward82715e12000-04-21 02:28:14 +000095 ]
96 display_option_names = map(lambda x: string.translate(x[0], longopt_xlate),
97 display_options)
98
99 # negative options are options that exclude other options
Greg Wardfe6462c2000-04-04 01:40:52 +0000100 negative_opt = {'quiet': 'verbose'}
101
102
103 # -- Creation/initialization methods -------------------------------
104
105 def __init__ (self, attrs=None):
106 """Construct a new Distribution instance: initialize all the
107 attributes of a Distribution, and then uses 'attrs' (a
108 dictionary mapping attribute names to values) to assign
109 some of those attributes their "real" values. (Any attributes
110 not mentioned in 'attrs' will be assigned to some null
111 value: 0, None, an empty list or dictionary, etc.) Most
112 importantly, initialize the 'command_obj' attribute
113 to the empty dictionary; this will be filled in with real
114 command objects by 'parse_command_line()'."""
115
116 # Default values for our command-line options
117 self.verbose = 1
118 self.dry_run = 0
Greg Wardfe6462c2000-04-04 01:40:52 +0000119 self.help = 0
Greg Ward82715e12000-04-21 02:28:14 +0000120 for attr in self.display_option_names:
121 setattr(self, attr, 0)
Greg Wardfe6462c2000-04-04 01:40:52 +0000122
Greg Ward82715e12000-04-21 02:28:14 +0000123 # Store the distribution meta-data (name, version, author, and so
124 # forth) in a separate object -- we're getting to have enough
125 # information here (and enough command-line options) that it's
126 # worth it. Also delegate 'get_XXX()' methods to the 'metadata'
127 # object in a sneaky and underhanded (but efficient!) way.
128 self.metadata = DistributionMetadata ()
Greg Ward4982f982000-04-22 02:52:44 +0000129 method_basenames = dir(self.metadata) + \
130 ['fullname', 'contact', 'contact_email']
131 for basename in method_basenames:
132 method_name = "get_" + basename
133 setattr(self, method_name, getattr(self.metadata, method_name))
Greg Wardfe6462c2000-04-04 01:40:52 +0000134
135 # 'cmdclass' maps command names to class objects, so we
136 # can 1) quickly figure out which class to instantiate when
137 # we need to create a new command object, and 2) have a way
Greg Ward82715e12000-04-21 02:28:14 +0000138 # for the setup script to override command classes
Greg Wardfe6462c2000-04-04 01:40:52 +0000139 self.cmdclass = {}
140
Gregory P. Smith14263542000-05-12 00:41:33 +0000141 # Store options for commands here between parsing them (from config
142 # files, the command-line, etc.) and actually putting them into the
143 # command object that needs them.
144 self.command_options = {}
145
Greg Wardfe6462c2000-04-04 01:40:52 +0000146 # These options are really the business of various commands, rather
147 # than of the Distribution itself. We provide aliases for them in
148 # Distribution as a convenience to the developer.
Greg Wardfe6462c2000-04-04 01:40:52 +0000149 self.packages = None
150 self.package_dir = None
151 self.py_modules = None
152 self.libraries = None
153 self.ext_modules = None
154 self.ext_package = None
155 self.include_dirs = None
156 self.extra_path = None
Gregory P. Smithb2e3bb32000-05-12 00:52:23 +0000157 self.scripts = None
Gregory P. Smith6a901dd2000-05-13 03:09:50 +0000158 self.data_files = None
Greg Wardfe6462c2000-04-04 01:40:52 +0000159
160 # And now initialize bookkeeping stuff that can't be supplied by
161 # the caller at all. 'command_obj' maps command names to
162 # Command instances -- that's how we enforce that every command
163 # class is a singleton.
164 self.command_obj = {}
165
166 # 'have_run' maps command names to boolean values; it keeps track
167 # of whether we have actually run a particular command, to make it
168 # cheap to "run" a command whenever we think we might need to -- if
169 # it's already been done, no need for expensive filesystem
170 # operations, we just check the 'have_run' dictionary and carry on.
171 # It's only safe to query 'have_run' for a command class that has
172 # been instantiated -- a false value will be inserted when the
173 # command object is created, and replaced with a true value when
174 # the command is succesfully run. Thus it's probably best to use
175 # '.get()' rather than a straight lookup.
176 self.have_run = {}
177
178 # Now we'll use the attrs dictionary (ultimately, keyword args from
Greg Ward82715e12000-04-21 02:28:14 +0000179 # the setup script) to possibly override any or all of these
180 # distribution options.
181
Greg Wardfe6462c2000-04-04 01:40:52 +0000182 if attrs:
183
184 # Pull out the set of command options and work on them
185 # specifically. Note that this order guarantees that aliased
186 # command options will override any supplied redundantly
187 # through the general options dictionary.
188 options = attrs.get ('options')
189 if options:
190 del attrs['options']
191 for (command, cmd_options) in options.items():
192 cmd_obj = self.find_command_obj (command)
193 for (key, val) in cmd_options.items():
194 cmd_obj.set_option (key, val)
195 # loop over commands
196 # if any command options
197
198 # Now work on the rest of the attributes. Any attribute that's
199 # not already defined is invalid!
200 for (key,val) in attrs.items():
Greg Ward82715e12000-04-21 02:28:14 +0000201 if hasattr (self.metadata, key):
202 setattr (self.metadata, key, val)
203 elif hasattr (self, key):
Greg Wardfe6462c2000-04-04 01:40:52 +0000204 setattr (self, key, val)
205 else:
Greg Ward02a1a2b2000-04-15 22:15:07 +0000206 raise DistutilsSetupError, \
Greg Wardfe6462c2000-04-04 01:40:52 +0000207 "invalid distribution option '%s'" % key
208
209 # __init__ ()
210
211
Gregory P. Smith14263542000-05-12 00:41:33 +0000212 def find_config_files (self):
213 """Find as many configuration files as should be processed for this
214 platform, and return a list of filenames in the order in which they
215 should be parsed. The filenames returned are guaranteed to exist
216 (modulo nasty race conditions).
217
218 On Unix, there are three possible config files: pydistutils.cfg in
219 the Distutils installation directory (ie. where the top-level
220 Distutils __inst__.py file lives), .pydistutils.cfg in the user's
221 home directory, and setup.cfg in the current directory.
222
223 On Windows and Mac OS, there are two possible config files:
224 pydistutils.cfg in the Python installation directory (sys.prefix)
225 and setup.cfg in the current directory."""
226
227 files = []
228 if os.name == "posix":
229 check_environ()
230
231 sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
232 sys_file = os.path.join(sys_dir, "pydistutils.cfg")
233 if os.path.isfile(sys_file):
234 files.append(sys_file)
235
236 user_file = os.path.join(os.environ.get('HOME'),
237 ".pydistutils.cfg")
238 if os.path.isfile(user_file):
239 files.append(user_file)
240
241 else:
242 sys_file = os.path.join (sysconfig.PREFIX, "pydistutils.cfg")
243 if os.path.isfile(sys_file):
244 files.append(sys_file)
245
246 # All platforms support local setup.cfg
247 local_file = "setup.cfg"
248 if os.path.isfile(local_file):
249 files.append(local_file)
250
251 return files
252
253 # find_config_files ()
254
255
256 def parse_config_files (self, filenames=None):
257
258 from ConfigParser import ConfigParser
259
260 if filenames is None:
261 filenames = self.find_config_files()
262
263 parser = ConfigParser()
264 parser.read(filenames)
265 for section in parser.sections():
266 options = parser.options(section)
267 if not self.command_options.has_key(section) is None:
268 self.command_options[section] = {}
269 cmd_opts = self.command_options[section]
270
271 for opt in options:
272 if opt != '__name__':
273 cmd_opts[opt] = parser.get(section,opt)
274
275 from pprint import pprint
276 print "configuration options:"
277 pprint (self.command_options)
278
279
Greg Wardfe6462c2000-04-04 01:40:52 +0000280 def parse_command_line (self, args):
281 """Parse the setup script's command line: set any Distribution
282 attributes tied to command-line options, create all command
283 objects, and set their options from the command-line. 'args'
284 must be a list of command-line arguments, most likely
285 'sys.argv[1:]' (see the 'setup()' function). This list is first
286 processed for "global options" -- options that set attributes of
287 the Distribution instance. Then, it is alternately scanned for
288 Distutils command and options for that command. Each new
289 command terminates the options for the previous command. The
290 allowed options for a command are determined by the 'options'
291 attribute of the command object -- thus, we instantiate (and
292 cache) every command object here, in order to access its
293 'options' attribute. Any error in that 'options' attribute
294 raises DistutilsGetoptError; any error on the command-line
295 raises DistutilsArgError. If no Distutils commands were found
296 on the command line, raises DistutilsArgError. Return true if
297 command-line successfully parsed and we should carry on with
298 executing commands; false if no errors but we shouldn't execute
299 commands (currently, this only happens if user asks for
300 help)."""
301
Greg Ward7d508fe2000-04-06 02:07:41 +0000302 # late import because of mutual dependence between these modules
Greg Wardfe6462c2000-04-04 01:40:52 +0000303 from distutils.cmd import Command
Greg Ward7d508fe2000-04-06 02:07:41 +0000304 from distutils.core import usage
Greg Wardfe6462c2000-04-04 01:40:52 +0000305
306 # We have to parse the command line a bit at a time -- global
307 # options, then the first command, then its options, and so on --
308 # because each command will be handled by a different class, and
309 # the options that are valid for a particular class aren't
310 # known until we instantiate the command class, which doesn't
311 # happen until we know what the command is.
312
313 self.commands = []
Greg Ward82715e12000-04-21 02:28:14 +0000314 parser = FancyGetopt (self.global_options + self.display_options)
315 parser.set_negative_aliases (self.negative_opt)
Greg Ward58ec6ed2000-04-21 04:22:49 +0000316 parser.set_aliases ({'license': 'licence'})
Greg Ward82715e12000-04-21 02:28:14 +0000317 args = parser.getopt (object=self)
318 option_order = parser.get_option_order()
Greg Wardfe6462c2000-04-04 01:40:52 +0000319
Greg Ward82715e12000-04-21 02:28:14 +0000320 # for display options we return immediately
321 if self.handle_display_options(option_order):
Greg Wardfe6462c2000-04-04 01:40:52 +0000322 return
323
324 while args:
325 # Pull the current command from the head of the command line
326 command = args[0]
327 if not command_re.match (command):
328 raise SystemExit, "invalid command name '%s'" % command
329 self.commands.append (command)
330
331 # Make sure we have a command object to put the options into
332 # (this either pulls it out of a cache of command objects,
333 # or finds and instantiates the command class).
334 try:
335 cmd_obj = self.find_command_obj (command)
336 except DistutilsModuleError, msg:
337 raise DistutilsArgError, msg
338
339 # Require that the command class be derived from Command --
Greg Wardc4537ac2000-05-07 15:30:31 +0000340 # want to be sure that the basic "command" interface is
341 # implemented.
Greg Wardfe6462c2000-04-04 01:40:52 +0000342 if not isinstance (cmd_obj, Command):
343 raise DistutilsClassError, \
344 "command class %s must subclass Command" % \
345 cmd_obj.__class__
346
347 # Also make sure that the command object provides a list of its
348 # known options
349 if not (hasattr (cmd_obj, 'user_options') and
350 type (cmd_obj.user_options) is ListType):
351 raise DistutilsClassError, \
352 ("command class %s must provide " +
353 "'user_options' attribute (a list of tuples)") % \
354 cmd_obj.__class__
355
356 # Poof! like magic, all commands support the global
357 # options too, just by adding in 'global_options'.
358 negative_opt = self.negative_opt
359 if hasattr (cmd_obj, 'negative_opt'):
360 negative_opt = copy (negative_opt)
361 negative_opt.update (cmd_obj.negative_opt)
362
Greg Ward82715e12000-04-21 02:28:14 +0000363 parser.set_option_table (self.global_options +
364 cmd_obj.user_options)
365 parser.set_negative_aliases (negative_opt)
366 args = parser.getopt (args[1:], cmd_obj)
Greg Wardfe6462c2000-04-04 01:40:52 +0000367 if cmd_obj.help:
Greg Ward82715e12000-04-21 02:28:14 +0000368 parser.set_option_table (self.global_options)
369 parser.print_help ("Global options:")
Greg Wardfe6462c2000-04-04 01:40:52 +0000370 print
Greg Ward82715e12000-04-21 02:28:14 +0000371
372 parser.set_option_table (cmd_obj.user_options)
373 parser.print_help ("Options for '%s' command:" % command)
Greg Wardfe6462c2000-04-04 01:40:52 +0000374 print
375 print usage
376 return
377
378 self.command_obj[command] = cmd_obj
379 self.have_run[command] = 0
380
381 # while args
382
383 # If the user wants help -- ie. they gave the "--help" option --
384 # give it to 'em. We do this *after* processing the commands in
385 # case they want help on any particular command, eg.
386 # "setup.py --help foo". (This isn't the documented way to
387 # get help on a command, but I support it because that's how
388 # CVS does it -- might as well be consistent.)
389 if self.help:
Greg Ward82715e12000-04-21 02:28:14 +0000390 parser.set_option_table (self.global_options)
391 parser.print_help (
392 "Global options (apply to all commands, " +
393 "or can be used per command):")
Greg Wardfe6462c2000-04-04 01:40:52 +0000394 print
395
Greg Ward82715e12000-04-21 02:28:14 +0000396 if not self.commands:
397 parser.set_option_table (self.display_options)
398 parser.print_help (
399 "Information display options (just display " +
400 "information, ignore any commands)")
401 print
402
Greg Wardfe6462c2000-04-04 01:40:52 +0000403 for command in self.commands:
404 klass = self.find_command_class (command)
Greg Ward82715e12000-04-21 02:28:14 +0000405 parser.set_option_table (klass.user_options)
406 parser.print_help ("Options for '%s' command:" % command)
Greg Wardfe6462c2000-04-04 01:40:52 +0000407 print
408
409 print usage
410 return
411
412 # Oops, no commands found -- an end-user error
413 if not self.commands:
414 raise DistutilsArgError, "no commands supplied"
415
416 # All is well: return true
417 return 1
418
419 # parse_command_line()
420
Greg Ward82715e12000-04-21 02:28:14 +0000421 def handle_display_options (self, option_order):
422 """If there were any non-global "display-only" options
423 (--help-commands or the metadata display options) on the command
424 line, display the requested info and return true; else return
425 false."""
426
427 from distutils.core import usage
428
429 # User just wants a list of commands -- we'll print it out and stop
430 # processing now (ie. if they ran "setup --help-commands foo bar",
431 # we ignore "foo bar").
432 if self.help_commands:
433 self.print_commands ()
434 print
435 print usage
436 return 1
437
438 # If user supplied any of the "display metadata" options, then
439 # display that metadata in the order in which the user supplied the
440 # metadata options.
441 any_display_options = 0
442 is_display_option = {}
443 for option in self.display_options:
444 is_display_option[option[0]] = 1
445
446 for (opt, val) in option_order:
447 if val and is_display_option.get(opt):
448 opt = string.translate (opt, longopt_xlate)
449 print getattr(self.metadata, "get_"+opt)()
450 any_display_options = 1
451
452 return any_display_options
453
454 # handle_display_options()
Greg Wardfe6462c2000-04-04 01:40:52 +0000455
456 def print_command_list (self, commands, header, max_length):
457 """Print a subset of the list of all commands -- used by
458 'print_commands()'."""
459
460 print header + ":"
461
462 for cmd in commands:
463 klass = self.cmdclass.get (cmd)
464 if not klass:
465 klass = self.find_command_class (cmd)
466 try:
467 description = klass.description
468 except AttributeError:
469 description = "(no description available)"
470
471 print " %-*s %s" % (max_length, cmd, description)
472
473 # print_command_list ()
474
475
476 def print_commands (self):
477 """Print out a help message listing all available commands with
478 a description of each. The list is divided into "standard
479 commands" (listed in distutils.command.__all__) and "extra
480 commands" (mentioned in self.cmdclass, but not a standard
481 command). The descriptions come from the command class
482 attribute 'description'."""
483
484 import distutils.command
485 std_commands = distutils.command.__all__
486 is_std = {}
487 for cmd in std_commands:
488 is_std[cmd] = 1
489
490 extra_commands = []
491 for cmd in self.cmdclass.keys():
492 if not is_std.get(cmd):
493 extra_commands.append (cmd)
494
495 max_length = 0
496 for cmd in (std_commands + extra_commands):
497 if len (cmd) > max_length:
498 max_length = len (cmd)
499
500 self.print_command_list (std_commands,
501 "Standard commands",
502 max_length)
503 if extra_commands:
504 print
505 self.print_command_list (extra_commands,
506 "Extra commands",
507 max_length)
508
509 # print_commands ()
510
511
512
513 # -- Command class/object methods ----------------------------------
514
Greg Wardfe6462c2000-04-04 01:40:52 +0000515 def find_command_class (self, command):
Gregory P. Smith14263542000-05-12 00:41:33 +0000516 """Given a command name, attempts to load the module and class that
517 implements that command. This is done by importing a module
518 "distutils.command." + command, and a class named 'command' in that
519 module.
Greg Wardfe6462c2000-04-04 01:40:52 +0000520
Gregory P. Smith14263542000-05-12 00:41:33 +0000521 Raises DistutilsModuleError if the expected module could not be
522 found, or if that module does not define the expected class."""
Greg Wardfe6462c2000-04-04 01:40:52 +0000523
524 module_name = 'distutils.command.' + command
525 klass_name = command
526
527 try:
528 __import__ (module_name)
529 module = sys.modules[module_name]
530 except ImportError:
531 raise DistutilsModuleError, \
532 "invalid command '%s' (no module named '%s')" % \
533 (command, module_name)
534
535 try:
536 klass = vars(module)[klass_name]
537 except KeyError:
538 raise DistutilsModuleError, \
539 "invalid command '%s' (no class '%s' in module '%s')" \
540 % (command, klass_name, module_name)
541
542 return klass
543
544 # find_command_class ()
545
546
547 def create_command_obj (self, command):
548 """Figure out the class that should implement a command,
549 instantiate it, cache and return the new "command object".
550 The "command class" is determined either by looking it up in
551 the 'cmdclass' attribute (this is the mechanism whereby
552 clients may override default Distutils commands or add their
553 own), or by calling the 'find_command_class()' method (if the
554 command name is not in 'cmdclass'."""
555
556 # Determine the command class -- either it's in the command_class
557 # dictionary, or we have to divine the module and class name
558 klass = self.cmdclass.get(command)
559 if not klass:
560 klass = self.find_command_class (command)
561 self.cmdclass[command] = klass
562
563 # Found the class OK -- instantiate it
564 cmd_obj = klass (self)
565 return cmd_obj
566
567
568 def find_command_obj (self, command, create=1):
569 """Look up and return a command object in the cache maintained by
570 'create_command_obj()'. If none found, the action taken
571 depends on 'create': if true (the default), create a new
572 command object by calling 'create_command_obj()' and return
573 it; otherwise, return None. If 'command' is an invalid
574 command name, then DistutilsModuleError will be raised."""
575
576 cmd_obj = self.command_obj.get (command)
577 if not cmd_obj and create:
578 cmd_obj = self.create_command_obj (command)
579 self.command_obj[command] = cmd_obj
580
581 return cmd_obj
582
583
584 # -- Methods that operate on the Distribution ----------------------
585
586 def announce (self, msg, level=1):
587 """Print 'msg' if 'level' is greater than or equal to the verbosity
588 level recorded in the 'verbose' attribute (which, currently,
589 can be only 0 or 1)."""
590
591 if self.verbose >= level:
592 print msg
593
594
595 def run_commands (self):
Greg Ward82715e12000-04-21 02:28:14 +0000596 """Run each command that was seen on the setup script command line.
Greg Wardfe6462c2000-04-04 01:40:52 +0000597 Uses the list of commands found and cache of command objects
598 created by 'create_command_obj()'."""
599
600 for cmd in self.commands:
601 self.run_command (cmd)
602
603
Greg Wardfe6462c2000-04-04 01:40:52 +0000604 # -- Methods that operate on its Commands --------------------------
605
606 def run_command (self, command):
607
608 """Do whatever it takes to run a command (including nothing at all,
609 if the command has already been run). Specifically: if we have
610 already created and run the command named by 'command', return
611 silently without doing anything. If the command named by
612 'command' doesn't even have a command object yet, create one.
613 Then invoke 'run()' on that command object (or an existing
614 one)."""
615
616 # Already been here, done that? then return silently.
617 if self.have_run.get (command):
618 return
619
620 self.announce ("running " + command)
621 cmd_obj = self.find_command_obj (command)
622 cmd_obj.ensure_ready ()
623 cmd_obj.run ()
624 self.have_run[command] = 1
625
626
Greg Wardfe6462c2000-04-04 01:40:52 +0000627 # -- Distribution query methods ------------------------------------
628
629 def has_pure_modules (self):
630 return len (self.packages or self.py_modules or []) > 0
631
632 def has_ext_modules (self):
633 return self.ext_modules and len (self.ext_modules) > 0
634
635 def has_c_libraries (self):
636 return self.libraries and len (self.libraries) > 0
637
638 def has_modules (self):
639 return self.has_pure_modules() or self.has_ext_modules()
640
641 def is_pure (self):
642 return (self.has_pure_modules() and
643 not self.has_ext_modules() and
644 not self.has_c_libraries())
645
Greg Ward82715e12000-04-21 02:28:14 +0000646 # -- Metadata query methods ----------------------------------------
647
648 # If you're looking for 'get_name()', 'get_version()', and so forth,
649 # they are defined in a sneaky way: the constructor binds self.get_XXX
650 # to self.metadata.get_XXX. The actual code is in the
651 # DistributionMetadata class, below.
652
653# class Distribution
654
655
656class DistributionMetadata:
657 """Dummy class to hold the distribution meta-data: name, version,
658 author, and so forth."""
659
660 def __init__ (self):
661 self.name = None
662 self.version = None
663 self.author = None
664 self.author_email = None
665 self.maintainer = None
666 self.maintainer_email = None
667 self.url = None
668 self.licence = None
669 self.description = None
Greg Warde5a584e2000-04-26 02:26:55 +0000670 self.long_description = None
Greg Ward82715e12000-04-21 02:28:14 +0000671
672 # -- Metadata query methods ----------------------------------------
673
Greg Wardfe6462c2000-04-04 01:40:52 +0000674 def get_name (self):
675 return self.name or "UNKNOWN"
676
Greg Ward82715e12000-04-21 02:28:14 +0000677 def get_version(self):
678 return self.version or "???"
Greg Wardfe6462c2000-04-04 01:40:52 +0000679
Greg Ward82715e12000-04-21 02:28:14 +0000680 def get_fullname (self):
681 return "%s-%s" % (self.get_name(), self.get_version())
682
683 def get_author(self):
684 return self.author or "UNKNOWN"
685
686 def get_author_email(self):
687 return self.author_email or "UNKNOWN"
688
689 def get_maintainer(self):
690 return self.maintainer or "UNKNOWN"
691
692 def get_maintainer_email(self):
693 return self.maintainer_email or "UNKNOWN"
694
695 def get_contact(self):
696 return (self.maintainer or
697 self.author or
698 "UNKNOWN")
699
700 def get_contact_email(self):
701 return (self.maintainer_email or
702 self.author_email or
703 "UNKNOWN")
704
705 def get_url(self):
706 return self.url or "UNKNOWN"
707
708 def get_licence(self):
709 return self.licence or "UNKNOWN"
710
711 def get_description(self):
712 return self.description or "UNKNOWN"
Greg Warde5a584e2000-04-26 02:26:55 +0000713
714 def get_long_description(self):
715 return self.long_description or "UNKNOWN"
716
Greg Ward82715e12000-04-21 02:28:14 +0000717# class DistributionMetadata
Greg Wardfe6462c2000-04-04 01:40:52 +0000718
719if __name__ == "__main__":
720 dist = Distribution ()
721 print "ok"