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.
This commit is contained in:
Éric Araujo 2011-10-21 06:27:06 +02:00
parent 3bb8be6d78
commit f89ebdc358
3 changed files with 74 additions and 17 deletions

View file

@ -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
%(func)s
%(split_multiline)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):