diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 6cb03b86648..bb18203e2de 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -295,7 +295,8 @@ Archiving operations *owner* and *group* are used when creating a tar archive. By default, uses the current owner and group. - *logger* is an instance of :class:`logging.Logger`. + *logger* must be an object compatible with :pep:`282`, usually an instance of + :class:`logging.Logger`. .. versionadded:: 3.2 diff --git a/Lib/fileinput.py b/Lib/fileinput.py index 554beb2448c..dbbbb2192ea 100644 --- a/Lib/fileinput.py +++ b/Lib/fileinput.py @@ -398,9 +398,8 @@ def hook_compressed(filename, mode): def hook_encoded(encoding): - import codecs def openhook(filename, mode): - return codecs.open(filename, mode, encoding) + return open(filename, mode, encoding=encoding) return openhook diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py index 97383d603e6..a516d735b8a 100644 --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -1,4 +1,4 @@ -"""HTTP cookie handling for web clients. +r"""HTTP cookie handling for web clients. This module has (now fairly distant) origins in Gisle Aas' Perl module HTTP::Cookies, from the libwww-perl library. diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 988cbed61c8..25acb3ffbef 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -35,11 +35,6 @@ __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'info', 'log', 'makeLogRecord', 'setLoggerClass', 'warn', 'warning', 'getLogRecordFactory', 'setLogRecordFactory', 'lastResort'] -try: - import codecs -except ImportError: #pragma: no cover - codecs = None - try: import threading except ImportError: #pragma: no cover @@ -954,8 +949,6 @@ class FileHandler(StreamHandler): """ #keep the absolute path, otherwise derived classes which use this #may come a cropper when the current directory changes - if codecs is None: #pragma: no cover - encoding = None self.baseFilename = os.path.abspath(filename) self.mode = mode self.encoding = encoding @@ -983,11 +976,7 @@ class FileHandler(StreamHandler): Open the current base file with the (original) mode and encoding. Return the resulting stream. """ - if self.encoding is None: - stream = open(self.baseFilename, self.mode) - else: - stream = codecs.open(self.baseFilename, self.mode, self.encoding) - return stream + return open(self.baseFilename, self.mode, encoding=self.encoding) def emit(self, record): """ diff --git a/Lib/logging/config.py b/Lib/logging/config.py index e183e74f9eb..5ef5c913a91 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -24,8 +24,8 @@ Copyright (C) 2001-2010 Vinay Sajip. All Rights Reserved. To use, simply 'import logging' and log away! """ -import sys, logging, logging.handlers, socket, struct, os, traceback, re -import types, io +import sys, logging, logging.handlers, socket, struct, traceback, re +import io try: import _thread as thread @@ -98,9 +98,6 @@ def _resolve(name): def _strip_spaces(alist): return map(lambda x: x.strip(), alist) -def _encoded(s): - return s if isinstance(s, str) else s.encode('utf-8') - def _create_formatters(cp): """Create and return formatters""" flist = cp["formatters"]["keys"] @@ -215,7 +212,7 @@ def _install_loggers(cp, handlers, disable_existing): #avoid disabling child loggers of explicitly #named loggers. With a sorted list it is easier #to find the child loggers. - existing.sort(key=_encoded) + existing.sort() #We'll keep the list of existing loggers #which are children of named loggers here... child_loggers = [] @@ -588,7 +585,7 @@ class DictConfigurator(BaseConfigurator): #avoid disabling child loggers of explicitly #named loggers. With a sorted list it is easier #to find the child loggers. - existing.sort(key=_encoded) + existing.sort() #We'll keep the list of existing loggers #which are children of named loggers here... child_loggers = [] @@ -804,7 +801,6 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT): struct.pack(">L", n), followed by the config file. Uses fileConfig() to do the grunt work. """ - import tempfile try: conn = self.connection chunk = conn.recv(4) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index ef17081908d..52e18e5410f 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -25,6 +25,7 @@ To use, simply 'import logging.handlers' and log away! """ import logging, socket, os, pickle, struct, time, re +from codecs import BOM_UTF8 from stat import ST_DEV, ST_INO, ST_MTIME import queue try: @@ -32,11 +33,6 @@ try: except ImportError: #pragma: no cover threading = None -try: - import codecs -except ImportError: #pragma: no cover - codecs = None - # # Some constants... # @@ -60,8 +56,6 @@ class BaseRotatingHandler(logging.FileHandler): """ Use the specified filename for streamed logging """ - if codecs is None: #pragma: no cover - encoding = None logging.FileHandler.__init__(self, filename, mode, encoding, delay) self.mode = mode self.encoding = encoding @@ -793,9 +787,7 @@ class SysLogHandler(logging.Handler): prio = prio.encode('utf-8') # Message is a string. Convert to bytes as required by RFC 5424 msg = msg.encode('utf-8') - if codecs: - msg = codecs.BOM_UTF8 + msg - msg = prio + msg + msg = prio + BOM_UTF8 + msg try: if self.unixsocket: try: diff --git a/Lib/packaging/command/bdist.py b/Lib/packaging/command/bdist.py index b9d550b86b3..e390cdc369d 100644 --- a/Lib/packaging/command/bdist.py +++ b/Lib/packaging/command/bdist.py @@ -126,7 +126,7 @@ class bdist(Command): # Reinitialize and run each command. for i in range(len(self.formats)): cmd_name = commands[i] - sub_cmd = self.get_reinitialized_command(cmd_name) + sub_cmd = self.reinitialize_command(cmd_name) sub_cmd.format = self.formats[i] # passing the owner and group names for tar archiving diff --git a/Lib/packaging/command/bdist_dumb.py b/Lib/packaging/command/bdist_dumb.py index 309f64fe1f7..548e3c4930c 100644 --- a/Lib/packaging/command/bdist_dumb.py +++ b/Lib/packaging/command/bdist_dumb.py @@ -80,8 +80,8 @@ class bdist_dumb(Command): if not self.skip_build: self.run_command('build') - install = self.get_reinitialized_command('install_dist', - reinit_subcommands=True) + install = self.reinitialize_command('install_dist', + reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False diff --git a/Lib/packaging/command/bdist_msi.py b/Lib/packaging/command/bdist_msi.py index 9c1791febaa..4f8eca6cc45 100644 --- a/Lib/packaging/command/bdist_msi.py +++ b/Lib/packaging/command/bdist_msi.py @@ -183,13 +183,13 @@ class bdist_msi(Command): if not self.skip_build: self.run_command('build') - install = self.get_reinitialized_command('install_dist', - reinit_subcommands=True) + install = self.reinitialize_command('install_dist', + reinit_subcommands=True) install.prefix = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False - install_lib = self.get_reinitialized_command('install_lib') + install_lib = self.reinitialize_command('install_lib') # we do not want to include pyc or pyo files install_lib.compile = False install_lib.optimize = 0 diff --git a/Lib/packaging/command/bdist_wininst.py b/Lib/packaging/command/bdist_wininst.py index 6c1e225f9f9..4e6b79ebe2e 100644 --- a/Lib/packaging/command/bdist_wininst.py +++ b/Lib/packaging/command/bdist_wininst.py @@ -115,14 +115,13 @@ class bdist_wininst(Command): if not self.skip_build: self.run_command('build') - install = self.get_reinitialized_command('install', - reinit_subcommands=True) + install = self.reinitialize_command('install', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False install.plat_name = self.plat_name - install_lib = self.get_reinitialized_command('install_lib') + install_lib = self.reinitialize_command('install_lib') # we do not want to include pyc or pyo files install_lib.compile = False install_lib.optimize = 0 diff --git a/Lib/packaging/command/cmd.py b/Lib/packaging/command/cmd.py index 1053ac390a5..a88df02a23e 100644 --- a/Lib/packaging/command/cmd.py +++ b/Lib/packaging/command/cmd.py @@ -318,8 +318,8 @@ class Command: cmd_obj.ensure_finalized() return cmd_obj - def get_reinitialized_command(self, command, reinit_subcommands=False): - return self.distribution.get_reinitialized_command( + def reinitialize_command(self, command, reinit_subcommands=False): + return self.distribution.reinitialize_command( command, reinit_subcommands) def run_command(self, command): diff --git a/Lib/packaging/command/install_dist.py b/Lib/packaging/command/install_dist.py index ce7015eeb46..c54da6f3dfa 100644 --- a/Lib/packaging/command/install_dist.py +++ b/Lib/packaging/command/install_dist.py @@ -55,9 +55,7 @@ class install_dist(Command): ('install-data=', None, "installation directory for data files"), - # Byte-compilation options -- see install_lib.py for details, as - # these are duplicated from there (but only install_lib does - # anything with them). + # Byte-compilation options -- see install_lib for details ('compile', 'c', "compile .py to .pyc [default]"), ('no-compile', None, "don't compile .py files"), ('optimize=', 'O', diff --git a/Lib/packaging/command/install_distinfo.py b/Lib/packaging/command/install_distinfo.py index 06ea4c1f806..b49729f5afa 100644 --- a/Lib/packaging/command/install_distinfo.py +++ b/Lib/packaging/command/install_distinfo.py @@ -16,8 +16,8 @@ class install_distinfo(Command): description = 'create a .dist-info directory for the distribution' user_options = [ - ('distinfo-dir=', None, - "directory where the the .dist-info directory will be installed"), + ('install-dir=', None, + "directory where the the .dist-info directory will be created"), ('installer=', None, "the name of the installer"), ('requested', None, @@ -35,7 +35,7 @@ class install_distinfo(Command): negative_opt = {'no-requested': 'requested'} def initialize_options(self): - self.distinfo_dir = None + self.install_dir = None self.installer = None self.requested = None self.no_record = None @@ -46,8 +46,7 @@ class install_distinfo(Command): self.set_undefined_options('install_dist', 'installer', 'requested', 'no_record') - self.set_undefined_options('install_lib', - ('install_dir', 'distinfo_dir')) + self.set_undefined_options('install_lib', 'install_dir') if self.installer is None: # FIXME distutils or packaging? @@ -64,26 +63,26 @@ class install_distinfo(Command): basename = metadata.get_fullname(filesafe=True) + ".dist-info" - self.distinfo_dir = os.path.join(self.distinfo_dir, basename) + self.install_dir = os.path.join(self.install_dir, basename) def run(self): - target = self.distinfo_dir + target = self.install_dir if os.path.isdir(target) and not os.path.islink(target): if not self.dry_run: rmtree(target) elif os.path.exists(target): - self.execute(os.unlink, (self.distinfo_dir,), + self.execute(os.unlink, (self.install_dir,), "removing " + target) self.execute(os.makedirs, (target,), "creating " + target) - metadata_path = os.path.join(self.distinfo_dir, 'METADATA') + metadata_path = os.path.join(self.install_dir, 'METADATA') self.execute(self.distribution.metadata.write, (metadata_path,), "creating " + metadata_path) self.outfiles.append(metadata_path) - installer_path = os.path.join(self.distinfo_dir, 'INSTALLER') + installer_path = os.path.join(self.install_dir, 'INSTALLER') logger.info('creating %s', installer_path) if not self.dry_run: with open(installer_path, 'w') as f: @@ -91,7 +90,7 @@ class install_distinfo(Command): self.outfiles.append(installer_path) if self.requested: - requested_path = os.path.join(self.distinfo_dir, 'REQUESTED') + requested_path = os.path.join(self.install_dir, 'REQUESTED') logger.info('creating %s', requested_path) if not self.dry_run: open(requested_path, 'wb').close() @@ -100,7 +99,7 @@ class install_distinfo(Command): if not self.no_resources: install_data = self.get_finalized_command('install_data') if install_data.get_resources_out() != []: - resources_path = os.path.join(self.distinfo_dir, + resources_path = os.path.join(self.install_dir, 'RESOURCES') logger.info('creating %s', resources_path) if not self.dry_run: @@ -114,7 +113,7 @@ class install_distinfo(Command): self.outfiles.append(resources_path) if not self.no_record: - record_path = os.path.join(self.distinfo_dir, 'RECORD') + record_path = os.path.join(self.install_dir, 'RECORD') logger.info('creating %s', record_path) if not self.dry_run: with open(record_path, 'w', encoding='utf-8') as f: diff --git a/Lib/packaging/command/test.py b/Lib/packaging/command/test.py index 7f9015bc8ec..5b62a128d42 100644 --- a/Lib/packaging/command/test.py +++ b/Lib/packaging/command/test.py @@ -56,7 +56,7 @@ class test(Command): prev_syspath = sys.path[:] try: # build release - build = self.get_reinitialized_command('build') + build = self.reinitialize_command('build') self.run_command('build') sys.path.insert(0, build.build_lib) diff --git a/Lib/packaging/create.py b/Lib/packaging/create.py index 59b448dc62e..5abe47b37dd 100644 --- a/Lib/packaging/create.py +++ b/Lib/packaging/create.py @@ -30,6 +30,7 @@ from textwrap import dedent from tokenize import detect_encoding from configparser import RawConfigParser +from packaging import logger # importing this with an underscore as it should be replaced by the # dict form or another structures for all purposes from packaging._trove import all_classifiers as _CLASSIFIERS_LIST @@ -124,7 +125,7 @@ def ask_yn(question, default=None, helptext=None): if answer and answer[0].lower() in ('y', 'n'): return answer[0].lower() - print('\nERROR: You must select "Y" or "N".\n') + logger.error('You must select "Y" or "N".') # XXX use util.ask @@ -147,10 +148,7 @@ def ask(question, default=None, helptext=None, required=True, helptext = helptext.strip("\n") while True: - sys.stdout.write(prompt) - sys.stdout.flush() - - line = sys.stdin.readline().strip() + line = input(prompt).strip() if line == '?': print('=' * 70) print(helptext) @@ -271,9 +269,10 @@ class MainProgram: def _write_cfg(self): if os.path.exists(_FILENAME): if os.path.exists('%s.old' % _FILENAME): - print("ERROR: %(name)s.old backup exists, please check that " - "current %(name)s is correct and remove %(name)s.old" % - {'name': _FILENAME}) + message = ("ERROR: %(name)s.old backup exists, please check " + "that current %(name)s is correct and remove " + "%(name)s.old" % {'name': _FILENAME}) + logger.error(message) return shutil.move(_FILENAME, '%s.old' % _FILENAME) @@ -320,7 +319,7 @@ class MainProgram: fp.write('\n') os.chmod(_FILENAME, 0o644) - print('Wrote "%s".' % _FILENAME) + logger.info('Wrote "%s".' % _FILENAME) def convert_py_to_cfg(self): """Generate a setup.cfg from an existing setup.py. @@ -614,8 +613,8 @@ class MainProgram: break if len(found_list) == 0: - print('ERROR: Could not find a matching license for "%s"' % - license) + logger.error('Could not find a matching license for "%s"' % + license) continue question = 'Matching licenses:\n\n' @@ -636,8 +635,8 @@ class MainProgram: try: index = found_list[int(choice) - 1] except ValueError: - print("ERROR: Invalid selection, type a number from the list " - "above.") + logger.error( + "Invalid selection, type a number from the list above.") classifiers.add(_CLASSIFIERS_LIST[index]) @@ -660,8 +659,8 @@ class MainProgram: classifiers.add(key) return except (IndexError, ValueError): - print("ERROR: Invalid selection, type a single digit " - "number.") + logger.error( + "Invalid selection, type a single digit number.") def main(): @@ -675,7 +674,3 @@ def main(): # program.write_setup_script() # packaging.util.cfg_to_args() program() - - -if __name__ == '__main__': - main() diff --git a/Lib/packaging/depgraph.py b/Lib/packaging/depgraph.py index 843aab47b08..d633b636ad8 100644 --- a/Lib/packaging/depgraph.py +++ b/Lib/packaging/depgraph.py @@ -224,6 +224,7 @@ def dependent_dists(dists, dist): def main(): + # XXX move to run._graph from packaging.database import get_distributions tempout = StringIO() try: @@ -267,7 +268,3 @@ def main(): else: print('Supported option: -d [filename]') sys.exit(1) - - -if __name__ == '__main__': - main() diff --git a/Lib/packaging/dist.py b/Lib/packaging/dist.py index 49ad4c5cc18..607767e971e 100644 --- a/Lib/packaging/dist.py +++ b/Lib/packaging/dist.py @@ -636,9 +636,9 @@ Common commands: (see '--help-commands' for more) except ValueError as msg: raise PackagingOptionError(msg) - def get_reinitialized_command(self, command, reinit_subcommands=False): + def reinitialize_command(self, command, reinit_subcommands=False): """Reinitializes a command to the state it was in when first - returned by 'get_command_obj()': ie., initialized but not yet + returned by 'get_command_obj()': i.e., initialized but not yet finalized. This provides the opportunity to sneak option values in programmatically, overriding or supplementing user-supplied values from the config files and command line. @@ -650,10 +650,11 @@ Common commands: (see '--help-commands' for more) 'reinit_subcommands' is true, also reinitializes the command's sub-commands, as declared by the 'sub_commands' class attribute (if it has one). See the "install_dist" command for an example. Only - reinitializes the sub-commands that actually matter, ie. those - whose test predicates return true. + reinitializes the sub-commands that actually matter, i.e. those + whose test predicate return true. - Returns the reinitialized command object. + Returns the reinitialized command object. It will be the same + object as the one stored in the self.command_obj attribute. """ if not isinstance(command, Command): command_name = command @@ -671,7 +672,7 @@ Common commands: (see '--help-commands' for more) if reinit_subcommands: for sub in command.get_sub_commands(): - self.get_reinitialized_command(sub, reinit_subcommands) + self.reinitialize_command(sub, reinit_subcommands) return command diff --git a/Lib/packaging/install.py b/Lib/packaging/install.py index b6816e56b29..776ba4014c3 100644 --- a/Lib/packaging/install.py +++ b/Lib/packaging/install.py @@ -527,12 +527,3 @@ def install(project): logger.info('%r conflicts with %s', project, ','.join(projects)) return True - - -def _main(**attrs): - if 'script_args' not in attrs: - attrs['requirements'] = sys.argv[1] - get_infos(**attrs) - -if __name__ == '__main__': - _main() diff --git a/Lib/packaging/tests/support.py b/Lib/packaging/tests/support.py index 66890c9b8e0..441efc06157 100644 --- a/Lib/packaging/tests/support.py +++ b/Lib/packaging/tests/support.py @@ -41,6 +41,9 @@ import tempfile import sysconfig from packaging.dist import Distribution +from packaging.util import resolve_name +from packaging.command import set_command, _COMMANDS + from packaging.tests import unittest from test.support import requires_zlib, unlink @@ -49,9 +52,10 @@ __all__ = [ # TestCase mixins 'LoggingCatcher', 'TempdirManager', 'EnvironRestorer', # mocks - 'DummyCommand', 'TestDistribution', + 'DummyCommand', 'TestDistribution', 'Inputs', # misc. functions and decorators - 'fake_dec', 'create_distribution', 'copy_xxmodule_c', 'fixup_build_ext', + 'fake_dec', 'create_distribution', 'use_command', + 'copy_xxmodule_c', 'fixup_build_ext', # imported from this module for backport purposes 'unittest', 'requires_zlib', 'skip_2to3_optimize', 'skip_unless_symlink', ] @@ -247,7 +251,7 @@ class DummyCommand: Useful for mocking one dependency command in the tests for another command, see e.g. the dummy build command in test_build_scripts. """ - # XXX does not work with dist.get_reinitialized_command, which typechecks + # XXX does not work with dist.reinitialize_command, which typechecks # and wants a finalized attribute def __init__(self, **kwargs): @@ -270,6 +274,22 @@ class TestDistribution(Distribution): return self._config_files +class Inputs: + """Fakes user inputs.""" + # TODO document usage + # TODO use context manager or something for auto cleanup + + def __init__(self, *answers): + self.answers = answers + self.index = 0 + + def __call__(self, prompt=''): + try: + return self.answers[self.index] + finally: + self.index += 1 + + def create_distribution(configfiles=()): """Prepares a distribution with given config files parsed.""" d = TestDistribution() @@ -280,6 +300,15 @@ def create_distribution(configfiles=()): return d +def use_command(testcase, fullname): + """Register command at *fullname* for the duration of a test.""" + set_command(fullname) + # XXX maybe set_command should return the class object + name = resolve_name(fullname).get_command_name() + # XXX maybe we need a public API to remove commands + testcase.addCleanup(_COMMANDS.__delitem__, name) + + def fake_dec(*args, **kw): """Fake decorator""" def _wrap(func): diff --git a/Lib/packaging/tests/test_command_build_ext.py b/Lib/packaging/tests/test_command_build_ext.py index 2926c37e875..4883f38a56b 100644 --- a/Lib/packaging/tests/test_command_build_ext.py +++ b/Lib/packaging/tests/test_command_build_ext.py @@ -3,7 +3,6 @@ import sys import site import sysconfig import textwrap -from io import StringIO from packaging.dist import Distribution from packaging.errors import (UnknownFileError, CompileError, PackagingPlatformError) @@ -11,7 +10,7 @@ from packaging.command.build_ext import build_ext from packaging.compiler.extension import Extension from test.script_helper import assert_python_ok -from packaging.tests import support, unittest, verbose +from packaging.tests import support, unittest class BuildExtTestCase(support.TempdirManager, @@ -37,18 +36,10 @@ class BuildExtTestCase(support.TempdirManager, support.fixup_build_ext(cmd) cmd.build_lib = self.tmp_dir cmd.build_temp = self.tmp_dir + cmd.ensure_finalized() + cmd.run() - old_stdout = sys.stdout - if not verbose: - # silence compiler output - sys.stdout = StringIO() - try: - cmd.ensure_finalized() - cmd.run() - finally: - sys.stdout = old_stdout - - code = """if 1: + code = textwrap.dedent("""\ import sys sys.path.insert(0, %r) @@ -63,7 +54,8 @@ class BuildExtTestCase(support.TempdirManager, doc = 'This is a template module just for instruction.' assert xx.__doc__ == doc assert isinstance(xx.Null(), xx.Null) - assert isinstance(xx.Str(), xx.Str)""" + assert isinstance(xx.Str(), xx.Str) + """) code = code % self.tmp_dir assert_python_ok('-c', code) @@ -388,16 +380,8 @@ class BuildExtTestCase(support.TempdirManager, cmd.build_temp = self.tmp_dir try: - old_stdout = sys.stdout - if not verbose: - # silence compiler output - sys.stdout = StringIO() - try: - cmd.ensure_finalized() - cmd.run() - finally: - sys.stdout = old_stdout - + cmd.ensure_finalized() + cmd.run() except CompileError: self.fail("Wrong deployment target during compilation") diff --git a/Lib/packaging/tests/test_command_build_py.py b/Lib/packaging/tests/test_command_build_py.py index 4d93faa0122..f7f26dafe9c 100644 --- a/Lib/packaging/tests/test_command_build_py.py +++ b/Lib/packaging/tests/test_command_build_py.py @@ -67,8 +67,6 @@ class BuildPyTestCase(support.TempdirManager, def test_empty_package_dir(self): # See SF 1668596/1720897. - cwd = os.getcwd() - # create the distribution files. sources = self.mkdtemp() pkg = os.path.join(sources, 'pkg') @@ -79,24 +77,16 @@ class BuildPyTestCase(support.TempdirManager, open(os.path.join(testdir, "testfile"), "wb").close() os.chdir(sources) - old_stdout = sys.stdout - #sys.stdout = StringIO.StringIO() + dist = Distribution({"packages": ["pkg"], + "package_dir": sources, + "package_data": {"pkg": ["doc/*"]}}) + dist.script_args = ["build"] + dist.parse_command_line() try: - dist = Distribution({"packages": ["pkg"], - "package_dir": sources, - "package_data": {"pkg": ["doc/*"]}}) - dist.script_args = ["build"] - dist.parse_command_line() - - try: - dist.run_commands() - except PackagingFileError: - self.fail("failed package_data test when package_dir is ''") - finally: - # Restore state. - os.chdir(cwd) - sys.stdout = old_stdout + dist.run_commands() + except PackagingFileError: + self.fail("failed package_data test when package_dir is ''") def test_byte_compile(self): project_dir, dist = self.create_dist(py_modules=['boiledeggs']) diff --git a/Lib/packaging/tests/test_command_clean.py b/Lib/packaging/tests/test_command_clean.py index ab944ed964f..a78c3a7a37d 100644 --- a/Lib/packaging/tests/test_command_clean.py +++ b/Lib/packaging/tests/test_command_clean.py @@ -36,8 +36,6 @@ class cleanTestCase(support.TempdirManager, support.LoggingCatcher, '%r was not removed' % path) # let's run the command again (should spit warnings but succeed) - cmd.all = True - cmd.ensure_finalized() cmd.run() diff --git a/Lib/packaging/tests/test_command_install_data.py b/Lib/packaging/tests/test_command_install_data.py index 94d6a215b36..8d4373d685d 100644 --- a/Lib/packaging/tests/test_command_install_data.py +++ b/Lib/packaging/tests/test_command_install_data.py @@ -62,6 +62,7 @@ class InstallDataTestCase(support.TempdirManager, # let's try with warn_dir one cmd.warn_dir = True + cmd.finalized = False cmd.ensure_finalized() cmd.run() @@ -80,6 +81,7 @@ class InstallDataTestCase(support.TempdirManager, cmd.data_files = {one: '{inst}/one', two: '{inst2}/two', three: '{inst3}/three'} + cmd.finalized = False cmd.ensure_finalized() cmd.run() diff --git a/Lib/packaging/tests/test_command_install_distinfo.py b/Lib/packaging/tests/test_command_install_distinfo.py index 6783d87e00f..33153e7fe3a 100644 --- a/Lib/packaging/tests/test_command_install_distinfo.py +++ b/Lib/packaging/tests/test_command_install_distinfo.py @@ -49,7 +49,7 @@ class InstallDistinfoTestCase(support.TempdirManager, cmd = install_distinfo(dist) dist.command_obj['install_distinfo'] = cmd - cmd.distinfo_dir = install_dir + cmd.install_dir = install_dir cmd.ensure_finalized() cmd.run() @@ -76,7 +76,7 @@ class InstallDistinfoTestCase(support.TempdirManager, cmd = install_distinfo(dist) dist.command_obj['install_distinfo'] = cmd - cmd.distinfo_dir = install_dir + cmd.install_dir = install_dir cmd.installer = 'bacon-python' cmd.ensure_finalized() cmd.run() @@ -96,7 +96,7 @@ class InstallDistinfoTestCase(support.TempdirManager, cmd = install_distinfo(dist) dist.command_obj['install_distinfo'] = cmd - cmd.distinfo_dir = install_dir + cmd.install_dir = install_dir cmd.requested = False cmd.ensure_finalized() cmd.run() @@ -116,7 +116,7 @@ class InstallDistinfoTestCase(support.TempdirManager, cmd = install_distinfo(dist) dist.command_obj['install_distinfo'] = cmd - cmd.distinfo_dir = install_dir + cmd.install_dir = install_dir cmd.no_record = True cmd.ensure_finalized() cmd.run() @@ -214,7 +214,7 @@ class InstallDistinfoTestCase(support.TempdirManager, cmd = install_distinfo(dist) dist.command_obj['install_distinfo'] = cmd - cmd.distinfo_dir = install_dir + cmd.install_dir = install_dir cmd.ensure_finalized() cmd.run() diff --git a/Lib/packaging/tests/test_command_register.py b/Lib/packaging/tests/test_command_register.py index 73d983439b0..07fad8998eb 100644 --- a/Lib/packaging/tests/test_command_register.py +++ b/Lib/packaging/tests/test_command_register.py @@ -12,6 +12,7 @@ except ImportError: DOCUTILS_SUPPORT = False from packaging.tests import unittest, support +from packaging.tests.support import Inputs from packaging.command import register as register_module from packaging.command.register import register from packaging.errors import PackagingSetupError @@ -38,19 +39,6 @@ password:password """ -class Inputs: - """Fakes user inputs.""" - def __init__(self, *answers): - self.answers = answers - self.index = 0 - - def __call__(self, prompt=''): - try: - return self.answers[self.index] - finally: - self.index += 1 - - class FakeOpener: """Fakes a PyPI server""" def __init__(self): @@ -143,6 +131,7 @@ class RegisterTestCase(support.TempdirManager, register_module.input = _no_way cmd.show_response = True + cmd.finalized = False cmd.ensure_finalized() cmd.run() diff --git a/Lib/packaging/tests/test_command_sdist.py b/Lib/packaging/tests/test_command_sdist.py index 34a2e9cd585..0b9f5be43d2 100644 --- a/Lib/packaging/tests/test_command_sdist.py +++ b/Lib/packaging/tests/test_command_sdist.py @@ -140,7 +140,7 @@ class SDistTestCase(support.TempdirManager, # now trying a tar then a gztar cmd.formats = ['tar', 'gztar'] - + cmd.finalized = False cmd.ensure_finalized() cmd.run() diff --git a/Lib/packaging/tests/test_config.py b/Lib/packaging/tests/test_config.py index e45fc11ab16..a0e96d0d052 100644 --- a/Lib/packaging/tests/test_config.py +++ b/Lib/packaging/tests/test_config.py @@ -1,7 +1,6 @@ """Tests for packaging.config.""" import os import sys -from io import StringIO from packaging import command from packaging.dist import Distribution @@ -183,13 +182,14 @@ class FooBarBazTest: def __init__(self, dist): self.distribution = dist + self._record = [] @classmethod def get_command_name(cls): return 'foo' def run(self): - self.distribution.foo_was_here = True + self._record.append('foo has run') def nothing(self): pass @@ -209,21 +209,11 @@ class ConfigTestCase(support.TempdirManager, def setUp(self): super(ConfigTestCase, self).setUp() - self.addCleanup(setattr, sys, 'stdout', sys.stdout) - self.addCleanup(setattr, sys, 'stderr', sys.stderr) - sys.stdout = StringIO() - sys.stderr = StringIO() - - self.addCleanup(os.chdir, os.getcwd()) tempdir = self.mkdtemp() self.working_dir = os.getcwd() os.chdir(tempdir) self.tempdir = tempdir - def tearDown(self): - os.chdir(self.working_dir) - super(ConfigTestCase, self).tearDown() - def write_setup(self, kwargs=None): opts = {'description-file': 'README', 'extra-files': '', 'setup-hooks': 'packaging.tests.test_config.version_hook'} @@ -378,7 +368,7 @@ class ConfigTestCase(support.TempdirManager, self.assertIn('hooks', sys.modules) def test_missing_setup_hook_warns(self): - self.write_setup({'setup-hooks': 'this.does._not.exist'}) + self.write_setup({'setup-hooks': 'does._not.exist'}) self.write_file('README', 'yeah') self.get_dist() logs = self.get_logs() @@ -491,10 +481,12 @@ class ConfigTestCase(support.TempdirManager, self.write_file((pkg, '__init__.py'), '#') # try to run the install command to see if foo is called + self.addCleanup(command._COMMANDS.__delitem__, 'foo') dist = self.get_dist() - self.assertIn('foo', command.get_command_names()) - self.assertEqual('FooBarBazTest', - dist.get_command_obj('foo').__class__.__name__) + dist.run_command('install_dist') + cmd = dist.get_command_obj('foo') + self.assertEqual(cmd.__class__.__name__, 'FooBarBazTest') + self.assertEqual(cmd._record, ['foo has run']) def test_suite(): diff --git a/Lib/packaging/tests/test_create.py b/Lib/packaging/tests/test_create.py index 16dbfb7fd4d..07824b1aa82 100644 --- a/Lib/packaging/tests/test_create.py +++ b/Lib/packaging/tests/test_create.py @@ -2,15 +2,17 @@ import os import sys import sysconfig -from io import StringIO from textwrap import dedent +from packaging import create from packaging.create import MainProgram, ask_yn, ask, main from packaging.tests import support, unittest +from packaging.tests.support import Inputs class CreateTestCase(support.TempdirManager, support.EnvironRestorer, + support.LoggingCatcher, unittest.TestCase): maxDiff = None @@ -18,11 +20,6 @@ class CreateTestCase(support.TempdirManager, def setUp(self): super(CreateTestCase, self).setUp() - self._stdin = sys.stdin # TODO use Inputs - self._stdout = sys.stdout - sys.stdin = StringIO() - sys.stdout = StringIO() - self._cwd = os.getcwd() self.wdir = self.mkdtemp() os.chdir(self.wdir) # patch sysconfig @@ -32,29 +29,24 @@ class CreateTestCase(support.TempdirManager, 'doc': sys.prefix + '/share/doc/pyxfoil', } def tearDown(self): - sys.stdin = self._stdin - sys.stdout = self._stdout - os.chdir(self._cwd) sysconfig.get_paths = self._old_get_paths + if hasattr(create, 'input'): + del create.input super(CreateTestCase, self).tearDown() def test_ask_yn(self): - sys.stdin.write('y\n') - sys.stdin.seek(0) + create.input = Inputs('y') self.assertEqual('y', ask_yn('is this a test')) def test_ask(self): - sys.stdin.write('a\n') - sys.stdin.write('b\n') - sys.stdin.seek(0) + create.input = Inputs('a', 'b') self.assertEqual('a', ask('is this a test')) self.assertEqual('b', ask(str(list(range(0, 70))), default='c', lengthy=True)) def test_set_multi(self): mainprogram = MainProgram() - sys.stdin.write('aaaaa\n') - sys.stdin.seek(0) + create.input = Inputs('aaaaa') mainprogram.data['author'] = [] mainprogram._set_multi('_set_multi test', 'author') self.assertEqual(['aaaaa'], mainprogram.data['author']) @@ -130,8 +122,7 @@ class CreateTestCase(support.TempdirManager, scripts=['my_script', 'bin/run'], ) """), encoding='utf-8') - sys.stdin.write('y\n') - sys.stdin.seek(0) + create.input = Inputs('y') main() path = os.path.join(self.wdir, 'setup.cfg') @@ -206,9 +197,7 @@ My super Death-scription barbar is now in the public domain, ho, baby! ''')) - sys.stdin.write('y\n') - sys.stdin.seek(0) - # FIXME Out of memory error. + create.input = Inputs('y') main() path = os.path.join(self.wdir, 'setup.cfg') diff --git a/Lib/packaging/tests/test_dist.py b/Lib/packaging/tests/test_dist.py index 3089f36f2ae..4cac842dd1f 100644 --- a/Lib/packaging/tests/test_dist.py +++ b/Lib/packaging/tests/test_dist.py @@ -6,30 +6,32 @@ import textwrap import packaging.dist from packaging.dist import Distribution -from packaging.command import set_command, _COMMANDS from packaging.command.cmd import Command from packaging.errors import PackagingModuleError, PackagingOptionError from packaging.tests import captured_stdout from packaging.tests import support, unittest -from packaging.tests.support import create_distribution +from packaging.tests.support import create_distribution, use_command from test.support import unload class test_dist(Command): - """Sample packaging extension command.""" + """Custom command used for testing.""" user_options = [ - ("sample-option=", "S", "help text"), + ('sample-option=', 'S', + "help text"), ] def initialize_options(self): self.sample_option = None + self._record = [] def finalize_options(self): - pass + if self.sample_option is None: + self.sample_option = 'default value' def run(self): - pass + self._record.append('test_dist has run') class DistributionTestCase(support.TempdirManager, @@ -45,14 +47,10 @@ class DistributionTestCase(support.TempdirManager, # (defaulting to sys.argv) self.argv = sys.argv, sys.argv[:] del sys.argv[1:] - self._commands = _COMMANDS.copy() def tearDown(self): sys.argv = self.argv[0] sys.argv[:] = self.argv[1] - # XXX maybe we need a public API to remove commands - _COMMANDS.clear() - _COMMANDS.update(self._commands) super(DistributionTestCase, self).tearDown() @unittest.skip('needs to be updated') @@ -181,7 +179,8 @@ class DistributionTestCase(support.TempdirManager, self.write_file((temp_home, "config2.cfg"), '[test_dist]\npre-hook.b = type') - set_command('packaging.tests.test_dist.test_dist') + use_command(self, 'packaging.tests.test_dist.test_dist') + dist = create_distribution(config_files) cmd = dist.get_command_obj("test_dist") self.assertEqual(cmd.pre_hook, {"a": 'type', "b": 'type'}) @@ -209,7 +208,7 @@ class DistributionTestCase(support.TempdirManager, record.append('post-%s' % cmd.get_command_name()) ''')) - set_command('packaging.tests.test_dist.test_dist') + use_command(self, 'packaging.tests.test_dist.test_dist') d = create_distribution([config_file]) cmd = d.get_command_obj("test_dist") @@ -236,7 +235,7 @@ class DistributionTestCase(support.TempdirManager, [test_dist] pre-hook.test = nonexistent.dotted.name''')) - set_command('packaging.tests.test_dist.test_dist') + use_command(self, 'packaging.tests.test_dist.test_dist') d = create_distribution([config_file]) cmd = d.get_command_obj("test_dist") cmd.ensure_finalized() @@ -251,7 +250,7 @@ class DistributionTestCase(support.TempdirManager, [test_dist] pre-hook.test = packaging.tests.test_dist.__doc__''')) - set_command('packaging.tests.test_dist.test_dist') + use_command(self, 'packaging.tests.test_dist.test_dist') d = create_distribution([config_file]) cmd = d.get_command_obj("test_dist") cmd.ensure_finalized() diff --git a/Lib/packaging/tests/test_run.py b/Lib/packaging/tests/test_run.py index d9460cf526c..84b9bf63af3 100644 --- a/Lib/packaging/tests/test_run.py +++ b/Lib/packaging/tests/test_run.py @@ -33,11 +33,9 @@ class RunTestCase(support.TempdirManager, def setUp(self): super(RunTestCase, self).setUp() - self.old_stdout = sys.stdout self.old_argv = sys.argv, sys.argv[:] def tearDown(self): - sys.stdout = self.old_stdout sys.argv = self.old_argv[0] sys.argv[:] = self.old_argv[1] super(RunTestCase, self).tearDown() diff --git a/Lib/packaging/tests/test_uninstall.py b/Lib/packaging/tests/test_uninstall.py index 2168b6fdf73..9e03b5433c8 100644 --- a/Lib/packaging/tests/test_uninstall.py +++ b/Lib/packaging/tests/test_uninstall.py @@ -1,6 +1,5 @@ """Tests for the packaging.uninstall module.""" import os -import sys import logging import packaging.util @@ -31,16 +30,12 @@ class UninstallTestCase(support.TempdirManager, def setUp(self): super(UninstallTestCase, self).setUp() - self.addCleanup(setattr, sys, 'stdout', sys.stdout) - self.addCleanup(setattr, sys, 'stderr', sys.stderr) - self.addCleanup(os.chdir, os.getcwd()) self.addCleanup(enable_cache) self.root_dir = self.mkdtemp() self.cwd = os.getcwd() disable_cache() def tearDown(self): - os.chdir(self.cwd) packaging.util._path_created.clear() super(UninstallTestCase, self).tearDown() diff --git a/Lib/packaging/tests/test_util.py b/Lib/packaging/tests/test_util.py index 00d61e0030a..262fef4d3d3 100644 --- a/Lib/packaging/tests/test_util.py +++ b/Lib/packaging/tests/test_util.py @@ -170,8 +170,8 @@ class UtilTestCase(support.EnvironRestorer, def unmock_popen(self): util.find_executable = self.old_find_executable subprocess.Popen = self.old_popen - sys.old_stdout = self.old_stdout - sys.old_stderr = self.old_stderr + sys.stdout = self.old_stdout + sys.stderr = self.old_stderr def test_convert_path(self): # linux/mac diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 276e6837055..0b79ffb90e2 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -488,8 +488,7 @@ def get_config_vars(*args): # Setting 'userbase' is done below the call to the # init function to enable using 'get_config_var' in # the init-function. - if sys.version >= '2.6': - _CONFIG_VARS['userbase'] = _getuserbase() + _CONFIG_VARS['userbase'] = _getuserbase() if 'srcdir' not in _CONFIG_VARS: _CONFIG_VARS['srcdir'] = _PROJECT_BASE diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index bbda525bea5..9fe7bbabc7c 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -172,6 +172,7 @@ import io import json import logging import os +import packaging.command import packaging.database import platform import random @@ -967,7 +968,7 @@ class saved_test_environment: 'sys.warnoptions', 'threading._dangling', 'multiprocessing.process._dangling', 'sysconfig._CONFIG_VARS', 'sysconfig._SCHEMES', - 'packaging.database_caches', + 'packaging.command._COMMANDS', 'packaging.database_caches', ) def get_sys_argv(self): @@ -1055,6 +1056,22 @@ class saved_test_environment: # Can't easily revert the logging state pass + def get_packaging_command__COMMANDS(self): + # registry mapping command names to full dotted path or to the actual + # class (resolved on demand); this check only looks at the names, not + # the types of the values (IOW, if a value changes from a string + # (dotted path) to a class it's okay but if a key (i.e. command class) + # is added we complain) + id_ = id(packaging.command._COMMANDS) + keys = set(packaging.command._COMMANDS) + return id_, keys + def restore_packaging_command__COMMANDS(self, saved): + # if command._COMMANDS was bound to another dict obhect, we can't + # restore the previous object and contents, because the get_ method + # above does not return the dict object (to ignore changes in values) + for key in packaging.command._COMMANDS.keys() - saved[1]: + del packaging.command._COMMANDS[key] + def get_packaging_database_caches(self): # caching system used by the PEP 376 implementation # we have one boolean and four dictionaries, initially empty diff --git a/Lib/test/test_fileinput.py b/Lib/test/test_fileinput.py index a96d48a5619..1e70641150d 100644 --- a/Lib/test/test_fileinput.py +++ b/Lib/test/test_fileinput.py @@ -7,8 +7,7 @@ import sys import re import fileinput import collections -import types -import codecs +import builtins import unittest try: @@ -807,18 +806,8 @@ class Test_hook_compressed(unittest.TestCase): @staticmethod def replace_builtin_open(new_open_func): - builtins_type = type(__builtins__) - if builtins_type is dict: - original_open = __builtins__["open"] - __builtins__["open"] = new_open_func - elif builtins_type is types.ModuleType: - original_open = __builtins__.open - __builtins__.open = new_open_func - else: - raise RuntimeError( - "unknown __builtins__ type: %r (unable to replace open)" % - builtins_type) - + original_open = builtins.open + builtins.open = new_open_func return original_open class Test_hook_encoded(unittest.TestCase): @@ -829,21 +818,22 @@ class Test_hook_encoded(unittest.TestCase): result = fileinput.hook_encoded(encoding) fake_open = InvocationRecorder() - original_open = codecs.open - codecs.open = fake_open + original_open = builtins.open + builtins.open = fake_open try: filename = object() mode = object() open_result = result(filename, mode) finally: - codecs.open = original_open + builtins.open = original_open self.assertEqual(fake_open.invocation_count, 1) - args = fake_open.last_invocation[0] + args, kwargs = fake_open.last_invocation self.assertIs(args[0], filename) self.assertIs(args[1], mode) - self.assertIs(args[2], encoding) + self.assertIs(kwargs.pop('encoding'), encoding) + self.assertFalse(kwargs) def test_main(): run_unittest( diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index ed22d91f0ca..25ca0b85535 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -49,6 +49,7 @@ import weakref try: import threading # The following imports are needed only for tests which + # require threading import asynchat import asyncore import errno @@ -95,9 +96,7 @@ class BaseTest(unittest.TestCase): finally: logging._releaseLock() - # Set two unused loggers: one non-ASCII and one Unicode. - # This is to test correct operation when sorting existing - # loggers in the configuration code. See issue 8201. + # Set two unused loggers self.logger1 = logging.getLogger("\xab\xd7\xbb") self.logger2 = logging.getLogger("\u013f\u00d6\u0047") @@ -310,8 +309,6 @@ class BuiltinLevelsTest(BaseTest): ('INF.BADPARENT', 'INFO', '4'), ]) - def test_invalid_name(self): - self.assertRaises(TypeError, logging.getLogger, any) class BasicFilterTest(BaseTest): @@ -3514,6 +3511,22 @@ class LoggerTest(BaseTest): self.addCleanup(setattr, self.logger.manager, 'disable', old_disable) self.assertFalse(self.logger.isEnabledFor(22)) + def test_root_logger_aliases(self): + root = logging.getLogger() + self.assertIs(root, logging.root) + self.assertIs(root, logging.getLogger(None)) + self.assertIs(root, logging.getLogger('')) + self.assertIs(root, logging.getLogger('foo').root) + self.assertIs(root, logging.getLogger('foo.bar').root) + self.assertIs(root, logging.getLogger('foo').parent) + + self.assertIsNot(root, logging.getLogger('\0')) + self.assertIsNot(root, logging.getLogger('foo.bar').parent) + + def test_invalid_names(self): + self.assertRaises(TypeError, logging.getLogger, any) + self.assertRaises(TypeError, logging.getLogger, b'foo') + class BaseFileTest(BaseTest): "Base class for handler tests that write log files" diff --git a/Lib/test/test_unicode_file.py b/Lib/test/test_unicode_file.py index 68bd658a754..45bcf5cbd1c 100644 --- a/Lib/test/test_unicode_file.py +++ b/Lib/test/test_unicode_file.py @@ -56,16 +56,20 @@ class TestUnicodeFiles(unittest.TestCase): # Should be able to rename the file using either name. self.assertTrue(os.path.isfile(filename1)) # must exist. os.rename(filename1, filename2 + ".new") - self.assertTrue(os.path.isfile(filename1+".new")) + self.assertFalse(os.path.isfile(filename2)) + self.assertTrue(os.path.isfile(filename1 + '.new')) os.rename(filename1 + ".new", filename2) + self.assertFalse(os.path.isfile(filename1 + '.new')) self.assertTrue(os.path.isfile(filename2)) shutil.copy(filename1, filename2 + ".new") os.unlink(filename1 + ".new") # remove using equiv name. # And a couple of moves, one using each name. shutil.move(filename1, filename2 + ".new") - self.assertTrue(not os.path.exists(filename2)) + self.assertFalse(os.path.exists(filename2)) + self.assertTrue(os.path.exists(filename1 + '.new')) shutil.move(filename1 + ".new", filename2) + self.assertFalse(os.path.exists(filename2 + '.new')) self.assertTrue(os.path.exists(filename1)) # Note - due to the implementation of shutil.move, # it tries a rename first. This only fails on Windows when on @@ -73,7 +77,9 @@ class TestUnicodeFiles(unittest.TestCase): # So we test the shutil.copy2 function, which is the thing most # likely to fail. shutil.copy2(filename1, filename2 + ".new") + self.assertTrue(os.path.isfile(filename1 + '.new')) os.unlink(filename1 + ".new") + self.assertFalse(os.path.exists(filename2 + '.new')) def _do_directory(self, make_name, chdir_name): cwd = os.getcwdb() diff --git a/Misc/NEWS b/Misc/NEWS index 51f68f4034f..6c19da8937e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -294,8 +294,6 @@ Core and Builtins - Issue #11320: fix bogus memory management in Modules/getpath.c, leading to a possible crash when calling Py_SetPath(). -- _ast.__version__ is now a Mercurial hex revision. - - Issue #11432: A bug was introduced in subprocess.Popen on posix systems with 3.2.0 where the stdout or stderr file descriptor being the same as the stdin file descriptor would raise an exception. webbrowser.open would fail. fixed. @@ -1555,8 +1553,6 @@ Extension Modules signature. Without this, architectures where sizeof void* != sizeof int are broken. Patch given by Hallvard B Furuseth. -- Issue #12221: Replace pyexpat.__version__ with the Python version. - - Issue #12051: Fix segfault in json.dumps() while encoding highly-nested objects using the C accelerations.