Commit 8962003f authored by Éric Araujo's avatar Éric Araujo

Remove display options (--name, etc.) from the Distribution class.

These options were used to implement “setup.py --name”,
“setup.py --version”, etc. which are now handled by the pysetup metadata
action or direct parsing of the setup.cfg file.

As a side effect, the Distribution class no longer accepts a 'url' key
in its *attrs* argument: it has to be 'home-page' to be recognized as a
valid metadata field and passed down to the dist.metadata object.

I cleaned up some comments, docstrings and code along the way.
parent 5b8e6bc5
"""Class representing the distribution being built/installed/etc.""" """Class representing the project being built/installed/etc."""
import os import os
import re import re
from packaging.errors import (PackagingOptionError, PackagingArgError,
PackagingModuleError, PackagingClassError)
from packaging.fancy_getopt import FancyGetopt
from packaging.util import strtobool, resolve_name
from packaging import logger from packaging import logger
from packaging.metadata import Metadata from packaging.util import strtobool, resolve_name
from packaging.config import Config from packaging.config import Config
from packaging.errors import (PackagingOptionError, PackagingArgError,
PackagingModuleError, PackagingClassError)
from packaging.command import get_command_class, STANDARD_COMMANDS from packaging.command import get_command_class, STANDARD_COMMANDS
from packaging.command.cmd import Command
from packaging.metadata import Metadata
from packaging.fancy_getopt import FancyGetopt
# Regex to define acceptable Packaging command names. This is not *quite* # Regex to define acceptable Packaging command names. This is not *quite*
# the same as a Python NAME -- I don't allow leading underscores. The fact # the same as a Python name -- leading underscores are not allowed. The fact
# that they're very similar is no coincidence; the default naming scheme is # that they're very similar is no coincidence: the default naming scheme is
# to look for a Python module named after the command. # to look for a Python module named after the command.
command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$')
...@@ -32,22 +33,16 @@ def gen_usage(script_name): ...@@ -32,22 +33,16 @@ def gen_usage(script_name):
class Distribution: class Distribution:
"""The core of the Packaging. Most of the work hiding behind 'setup' """Class used to represent a project and work with it.
is really done within a Distribution instance, which farms the work out
to the Packaging commands specified on the command line. Most of the work hiding behind 'pysetup run' is really done within a
Distribution instance, which farms the work out to the commands
Setup scripts will almost never instantiate Distribution directly, specified on the command line.
unless the 'setup()' function is totally inadequate to their needs.
However, it is conceivable that a setup script might wish to subclass
Distribution for some specialized purpose, and then pass the subclass
to 'setup()' as the 'distclass' keyword argument. If so, it is
necessary to respect the expectations that 'setup' has of Distribution.
See the code for 'setup()', in run.py, for details.
""" """
# 'global_options' describes the command-line options that may be # 'global_options' describes the command-line options that may be
# supplied to the setup script prior to any actual commands. # supplied to the setup script prior to any actual commands.
# Eg. "pysetup -n" or "pysetup --dry-run" both take advantage of # Eg. "pysetup run -n" or "pysetup run --dry-run" both take advantage of
# these global options. This list should be kept to a bare minimum, # these global options. This list should be kept to a bare minimum,
# since every global option is also valid as a command option -- and we # since every global option is also valid as a command option -- and we
# don't want to pollute the commands with too many options that they # don't want to pollute the commands with too many options that they
...@@ -63,55 +58,14 @@ class Distribution: ...@@ -63,55 +58,14 @@ class Distribution:
common_usage = """\ common_usage = """\
Common commands: (see '--help-commands' for more) Common commands: (see '--help-commands' for more)
pysetup run build will build the package underneath 'build/' pysetup run build will build the project underneath 'build/'
pysetup run install will install the package pysetup run install will install the project
""" """
# options that are not propagated to the commands # options that are not propagated to the commands
display_options = [ display_options = [
('help-commands', None, ('help-commands', None,
"list all available commands"), "list all available commands"),
# XXX this is obsoleted by the pysetup metadata action
('name', None,
"print package name"),
('version', 'V',
"print package version"),
('fullname', None,
"print <package name>-<version>"),
('author', None,
"print the author's name"),
('author-email', None,
"print the author's email address"),
('maintainer', None,
"print the maintainer's name"),
('maintainer-email', None,
"print the maintainer's email address"),
('contact', None,
"print the maintainer's name if known, else the author's"),
('contact-email', None,
"print the maintainer's email address if known, else the author's"),
('url', None,
"print the URL for this package"),
('license', None,
"print the license of the package"),
('licence', None,
"alias for --license"),
('description', None,
"print the package description"),
('long-description', None,
"print the long package description"),
('platforms', None,
"print the list of platforms"),
('classifier', None,
"print the list of classifiers"),
('keywords', None,
"print the list of keywords"),
('provides', None,
"print the list of packages/modules provided"),
('requires', None,
"print the list of packages/modules required"),
('obsoletes', None,
"print the list of packages/modules made obsolete"),
('use-2to3', None, ('use-2to3', None,
"use 2to3 to make source python 3.x compatible"), "use 2to3 to make source python 3.x compatible"),
('convert-2to3-doctests', None, ('convert-2to3-doctests', None,
...@@ -347,7 +301,6 @@ Common commands: (see '--help-commands' for more) ...@@ -347,7 +301,6 @@ Common commands: (see '--help-commands' for more)
self.commands = [] self.commands = []
parser = FancyGetopt(toplevel_options + self.display_options) parser = FancyGetopt(toplevel_options + self.display_options)
parser.set_negative_aliases(self.negative_opt) parser.set_negative_aliases(self.negative_opt)
parser.set_aliases({'licence': 'license'})
args = parser.getopt(args=self.script_args, object=self) args = parser.getopt(args=self.script_args, object=self)
option_order = parser.get_option_order() option_order = parser.get_option_order()
...@@ -372,7 +325,7 @@ Common commands: (see '--help-commands' for more) ...@@ -372,7 +325,7 @@ Common commands: (see '--help-commands' for more)
commands=self.commands) commands=self.commands)
return return
return 1 return True
def _get_toplevel_options(self): def _get_toplevel_options(self):
"""Return the non-display options recognized at the top level. """Return the non-display options recognized at the top level.
...@@ -496,13 +449,10 @@ Common commands: (see '--help-commands' for more) ...@@ -496,13 +449,10 @@ Common commands: (see '--help-commands' for more)
If 'global_options' is true, lists the global options: If 'global_options' is true, lists the global options:
--dry-run, etc. If 'display_options' is true, lists --dry-run, etc. If 'display_options' is true, lists
the "display-only" options: --name, --version, etc. Finally, the "display-only" options: --help-commands. Finally,
lists per-command help for every command name or command class lists per-command help for every command name or command class
in 'commands'. in 'commands'.
""" """
# late import because of mutual dependence between these modules
from packaging.command.cmd import Command
if global_options: if global_options:
if display_options: if display_options:
options = self._get_toplevel_options() options = self._get_toplevel_options()
...@@ -536,9 +486,8 @@ Common commands: (see '--help-commands' for more) ...@@ -536,9 +486,8 @@ Common commands: (see '--help-commands' for more)
def handle_display_options(self, option_order): def handle_display_options(self, option_order):
"""If there were any non-global "display-only" options """If there were any non-global "display-only" options
(--help-commands or the metadata display options) on the command (--help-commands) on the command line, display the requested info and
line, display the requested info and return true; else return return true; else return false.
false.
""" """
# User just wants a list of commands -- we'll print it out and stop # User just wants a list of commands -- we'll print it out and stop
# processing now (ie. if they ran "setup --help-commands foo bar", # processing now (ie. if they ran "setup --help-commands foo bar",
...@@ -547,7 +496,7 @@ Common commands: (see '--help-commands' for more) ...@@ -547,7 +496,7 @@ Common commands: (see '--help-commands' for more)
self.print_commands() self.print_commands()
print() print()
print(gen_usage(self.script_name)) print(gen_usage(self.script_name))
return 1 return True
# If user supplied any of the "display metadata" options, then # If user supplied any of the "display metadata" options, then
# display that metadata in the order in which the user supplied the # display that metadata in the order in which the user supplied the
...@@ -628,18 +577,17 @@ Common commands: (see '--help-commands' for more) ...@@ -628,18 +577,17 @@ Common commands: (see '--help-commands' for more)
""" """
cmd_obj = self.command_obj.get(command) cmd_obj = self.command_obj.get(command)
if not cmd_obj and create: if not cmd_obj and create:
logger.debug("Distribution.get_command_obj(): " \ logger.debug("Distribution.get_command_obj(): "
"creating %r command object", command) "creating %r command object", command)
cls = get_command_class(command) cls = get_command_class(command)
cmd_obj = self.command_obj[command] = cls(self) cmd_obj = self.command_obj[command] = cls(self)
self.have_run[command] = 0 self.have_run[command] = 0
# Set any options that were supplied in config files # Set any options that were supplied in config files or on the
# or on the command line. (NB. support for error # command line. (XXX support for error reporting is suboptimal
# reporting is lame here: any errors aren't reported # here: errors aren't reported until finalize_options is called,
# until 'finalize_options()' is called, which means # which means we won't report the source of the error.)
# we won't report the source of the error.)
options = self.command_options.get(command) options = self.command_options.get(command)
if options: if options:
self._set_command_options(cmd_obj, options) self._set_command_options(cmd_obj, options)
...@@ -707,7 +655,6 @@ Common commands: (see '--help-commands' for more) ...@@ -707,7 +655,6 @@ Common commands: (see '--help-commands' for more)
Returns the reinitialized command object. Returns the reinitialized command object.
""" """
from packaging.command.cmd import Command
if not isinstance(command, Command): if not isinstance(command, Command):
command_name = command command_name = command
command = self.get_command_obj(command_name) command = self.get_command_obj(command_name)
...@@ -716,6 +663,7 @@ Common commands: (see '--help-commands' for more) ...@@ -716,6 +663,7 @@ Common commands: (see '--help-commands' for more)
if not command.finalized: if not command.finalized:
return command return command
command.initialize_options() command.initialize_options()
self.have_run[command_name] = 0 self.have_run[command_name] = 0
command.finalized = False command.finalized = False
......
...@@ -35,7 +35,7 @@ class BuildDumbTestCase(support.TempdirManager, ...@@ -35,7 +35,7 @@ class BuildDumbTestCase(support.TempdirManager,
dist = Distribution({'name': 'foo', 'version': '0.1', dist = Distribution({'name': 'foo', 'version': '0.1',
'py_modules': ['foo'], 'py_modules': ['foo'],
'url': 'xxx', 'author': 'xxx', 'home-page': 'xxx', 'author': 'xxx',
'author_email': 'xxx'}) 'author_email': 'xxx'})
os.chdir(pkg_dir) os.chdir(pkg_dir)
cmd = bdist_dumb(dist) cmd = bdist_dumb(dist)
......
...@@ -99,7 +99,7 @@ class RegisterTestCase(support.TempdirManager, ...@@ -99,7 +99,7 @@ class RegisterTestCase(support.TempdirManager,
def _get_cmd(self, metadata=None): def _get_cmd(self, metadata=None):
if metadata is None: if metadata is None:
metadata = {'url': 'xxx', 'author': 'xxx', metadata = {'home-page': 'xxx', 'author': 'xxx',
'author_email': 'xxx', 'author_email': 'xxx',
'name': 'xxx', 'version': 'xxx'} 'name': 'xxx', 'version': 'xxx'}
pkg_info, dist = self.create_dist(**metadata) pkg_info, dist = self.create_dist(**metadata)
......
...@@ -72,7 +72,7 @@ class SDistTestCase(support.TempdirManager, ...@@ -72,7 +72,7 @@ class SDistTestCase(support.TempdirManager,
"""Returns a cmd""" """Returns a cmd"""
if metadata is None: if metadata is None:
metadata = {'name': 'fake', 'version': '1.0', metadata = {'name': 'fake', 'version': '1.0',
'url': 'xxx', 'author': 'xxx', 'home_page': 'xxx', 'author': 'xxx',
'author_email': 'xxx'} 'author_email': 'xxx'}
dist = Distribution(metadata) dist = Distribution(metadata)
dist.packages = ['somecode'] dist.packages = ['somecode']
......
...@@ -98,7 +98,7 @@ class DistributionTestCase(support.TempdirManager, ...@@ -98,7 +98,7 @@ class DistributionTestCase(support.TempdirManager,
Distribution(attrs={'author': 'xxx', Distribution(attrs={'author': 'xxx',
'name': 'xxx', 'name': 'xxx',
'version': '1.2', 'version': '1.2',
'url': 'xxxx', 'home-page': 'xxxx',
'badoptname': 'xxx'}) 'badoptname': 'xxx'})
logs = self.get_logs(logging.WARNING) logs = self.get_logs(logging.WARNING)
self.assertEqual(1, len(logs)) self.assertEqual(1, len(logs))
...@@ -108,7 +108,7 @@ class DistributionTestCase(support.TempdirManager, ...@@ -108,7 +108,7 @@ class DistributionTestCase(support.TempdirManager,
Distribution(attrs={'author': 'xxx', Distribution(attrs={'author': 'xxx',
'name': 'xxx', 'name': 'xxx',
'version': 'xxx', 'version': 'xxx',
'url': 'xxxx'}) 'home-page': 'xxxx'})
logs = self.get_logs(logging.WARNING) logs = self.get_logs(logging.WARNING)
self.assertEqual(1, len(logs)) self.assertEqual(1, len(logs))
self.assertIn('not a valid version', logs[0]) self.assertIn('not a valid version', logs[0])
...@@ -119,7 +119,7 @@ class DistributionTestCase(support.TempdirManager, ...@@ -119,7 +119,7 @@ class DistributionTestCase(support.TempdirManager,
Distribution(attrs={'author': 'xxx', Distribution(attrs={'author': 'xxx',
'name': 'xxx', 'name': 'xxx',
'version': '1.2', 'version': '1.2',
'url': 'xxxx', 'home-page': 'xxxx',
'options': {}}) 'options': {}})
self.assertEqual([], self.get_logs(logging.WARNING)) self.assertEqual([], self.get_logs(logging.WARNING))
...@@ -135,7 +135,7 @@ class DistributionTestCase(support.TempdirManager, ...@@ -135,7 +135,7 @@ class DistributionTestCase(support.TempdirManager,
dist = Distribution(attrs={'author': 'xxx', dist = Distribution(attrs={'author': 'xxx',
'name': 'xxx', 'name': 'xxx',
'version': 'xxx', 'version': 'xxx',
'url': 'xxxx', 'home-page': 'xxxx',
'options': {'sdist': {'owner': 'root'}}}) 'options': {'sdist': {'owner': 'root'}}})
self.assertIn('owner', dist.get_option_dict('sdist')) self.assertIn('owner', dist.get_option_dict('sdist'))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment