diff options
author | Éric Araujo <merwok@netwok.org> | 2011-10-21 04:27:06 (GMT) |
---|---|---|
committer | Éric Araujo <merwok@netwok.org> | 2011-10-21 04:27:06 (GMT) |
commit | f89ebdc358402588db893e18e4dd31bc8272b7bf (patch) | |
tree | 99c00698f86d45cc7d747e6d15be3528e0d02db4 | |
parent | 3bb8be6d78130dfcf49c4860f0009300508ff92b (diff) | |
download | cpython-f89ebdc358402588db893e18e4dd31bc8272b7bf.zip cpython-f89ebdc358402588db893e18e4dd31bc8272b7bf.tar.gz cpython-f89ebdc358402588db893e18e4dd31bc8272b7bf.tar.bz2 |
Fix missing imports in setup scripts generated by packaging (#13205).
I’ve made more edits than the bug report suggested to make sure the
generated setup script is compatible with many Python versions; a
comment in the source explains that in detail.
The cfg_to_args function uses old 2.x idioms like codecs.open and
RawConfigParser.readfp because I want the setup.py generated by packaging and
distutils2 to be the same. Most users won’t see the deprecation warning and I
ignore it in the test suite.
Thanks to David Barnett for the report and original patch.
-rw-r--r-- | Lib/packaging/tests/test_util.py | 34 | ||||
-rw-r--r-- | Lib/packaging/util.py | 56 | ||||
-rw-r--r-- | Misc/ACKS | 1 |
3 files changed, 74 insertions, 17 deletions
diff --git a/Lib/packaging/tests/test_util.py b/Lib/packaging/tests/test_util.py index 92aa72a..1cf5c93 100644 --- a/Lib/packaging/tests/test_util.py +++ b/Lib/packaging/tests/test_util.py @@ -5,11 +5,10 @@ import time import logging import tempfile import textwrap +import warnings import subprocess from io import StringIO -from packaging.tests import support, unittest -from packaging.tests.test_config import SETUP_CFG from packaging.errors import ( PackagingPlatformError, PackagingByteCompileError, PackagingFileError, PackagingExecError, InstallationException) @@ -20,7 +19,11 @@ from packaging.util import ( get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages, spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob, RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging, - get_install_method, cfg_to_args, encode_multipart) + get_install_method, cfg_to_args, generate_setup_py, encode_multipart) + +from packaging.tests import support, unittest +from packaging.tests.test_config import SETUP_CFG +from test.script_helper import assert_python_ok, assert_python_failure PYPIRC = """\ @@ -513,7 +516,9 @@ class UtilTestCase(support.EnvironRestorer, self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8') self.write_file('README', 'loooong description') - args = cfg_to_args() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + args = cfg_to_args() # use Distribution to get the contents of the setup.cfg file dist = Distribution() dist.parse_config_files() @@ -539,6 +544,26 @@ class UtilTestCase(support.EnvironRestorer, self.assertEqual(args['scripts'], dist.scripts) self.assertEqual(args['py_modules'], dist.py_modules) + def test_generate_setup_py(self): + # undo subprocess.Popen monkey-patching before using assert_python_* + subprocess.Popen = self.old_popen + os.chdir(self.mkdtemp()) + self.write_file('setup.cfg', textwrap.dedent("""\ + [metadata] + name = SPAM + classifier = Programming Language :: Python + """)) + generate_setup_py() + self.assertTrue(os.path.exists('setup.py'), 'setup.py not created') + rc, out, err = assert_python_ok('setup.py', '--name') + self.assertEqual(out, b'SPAM\n') + self.assertEqual(err, b'') + + # a generated setup.py should complain if no setup.cfg is present + os.unlink('setup.cfg') + rc, out, err = assert_python_failure('setup.py', '--name') + self.assertIn(b'setup.cfg', err) + def test_encode_multipart(self): fields = [('username', 'wok'), ('password', 'secret')] files = [('picture', 'wok.png', b'PNG89')] @@ -590,7 +615,6 @@ class GlobTestCase(GlobTestCaseBase): super(GlobTestCase, self).tearDown() def assertGlobMatch(self, glob, spec): - """""" tempdir = self.build_files_tree(spec) expected = self.clean_tree(spec) os.chdir(tempdir) diff --git a/Lib/packaging/util.py b/Lib/packaging/util.py index 2af1149..8dd715f 100644 --- a/Lib/packaging/util.py +++ b/Lib/packaging/util.py @@ -6,6 +6,7 @@ import csv import imp import sys import errno +import codecs import shutil import string import hashlib @@ -417,7 +418,8 @@ byte_compile(files, optimize=%r, force=%r, # cfile - byte-compiled file # dfile - purported source filename (same as 'file' by default) if optimize >= 0: - cfile = imp.cache_from_source(file, debug_override=not optimize) + cfile = imp.cache_from_source(file, + debug_override=not optimize) else: cfile = imp.cache_from_source(file) dfile = file @@ -931,6 +933,24 @@ def _iglob(path_glob): yield file +# HOWTO change cfg_to_args +# +# This function has two major constraints: It is copied by inspect.getsource +# in generate_setup_py; it is used in generated setup.py which may be run by +# any Python version supported by distutils2 (2.4-3.3). +# +# * Keep objects like D1_D2_SETUP_ARGS static, i.e. in the function body +# instead of global. +# * If you use a function from another module, update the imports in +# SETUP_TEMPLATE. Use only modules, classes and functions compatible with +# all versions: codecs.open instead of open, RawConfigParser.readfp instead +# of read, standard exceptions instead of Packaging*Error, etc. +# * If you use a function from this module, update the template and +# generate_setup_py. +# +# test_util tests this function and the generated setup.py, but does not test +# that it's compatible with all Python versions. + def cfg_to_args(path='setup.cfg'): """Compatibility helper to use setup.cfg in setup.py. @@ -941,8 +961,6 @@ def cfg_to_args(path='setup.cfg'): *file* is the path to the setup.cfg file. If it doesn't exist, PackagingFileError is raised. """ - # We need to declare the following constants here so that it's easier to - # generate the setup.py afterwards, using inspect.getsource. # XXX ** == needs testing D1_D2_SETUP_ARGS = {"name": ("metadata",), @@ -986,10 +1004,11 @@ def cfg_to_args(path='setup.cfg'): # The real code starts here config = RawConfigParser() - if not os.path.exists(path): - raise PackagingFileError("file '%s' does not exist" % - os.path.abspath(path)) - config.read(path, encoding='utf-8') + f = codecs.open(path, encoding='utf-8') + try: + config.readfp(f) + finally: + f.close() kwargs = {} for arg in D1_D2_SETUP_ARGS: @@ -1011,8 +1030,11 @@ def cfg_to_args(path='setup.cfg'): filenames = split_multiline(filenames) in_cfg_value = [] for filename in filenames: - with open(filename) as fp: + fp = codecs.open(filename, encoding='utf-8') + try: in_cfg_value.append(fp.read()) + finally: + fp.close() in_cfg_value = '\n\n'.join(in_cfg_value) else: continue @@ -1029,13 +1051,19 @@ def cfg_to_args(path='setup.cfg'): return kwargs -_SETUP_TMPL = """\ +SETUP_TEMPLATE = """\ # This script was automatically generated by packaging import os +import codecs from distutils.core import setup -from ConfigParser import RawConfigParser +try: + from ConfigParser import RawConfigParser +except ImportError: + from configparser import RawConfigParser + +%(split_multiline)s -%(func)s +%(cfg_to_args)s setup(**cfg_to_args()) """ @@ -1049,8 +1077,10 @@ def generate_setup_py(): if os.path.exists("setup.py"): raise PackagingFileError("a setup.py file already exists") + source = SETUP_TEMPLATE % {'split_multiline': getsource(split_multiline), + 'cfg_to_args': getsource(cfg_to_args)} with open("setup.py", "w", encoding='utf-8') as fp: - fp.write(_SETUP_TMPL % {'func': getsource(cfg_to_args)}) + fp.write(source) # Taken from the pip project @@ -1307,6 +1337,8 @@ def get_install_method(path): def copy_tree(src, dst, preserve_mode=True, preserve_times=True, preserve_symlinks=False, update=False, verbose=True, dry_run=False): + # FIXME use of this function is why we get spurious logging message on + # stdout when tests run; kill and replace by shuil! from distutils.file_util import copy_file if not dry_run and not os.path.isdir(src): @@ -56,6 +56,7 @@ Nicolas Bareil Chris Barker Nick Barnes Quentin Barnes +David Barnett Richard Barran Cesar Eduardo Barros Des Barry |