Banch merge

This commit is contained in:
Éric Araujo 2011-10-21 15:52:10 +02:00
commit 3764a964ca
7 changed files with 161 additions and 18 deletions

View file

@ -675,3 +675,7 @@ extension modules.
| | abort the build process, but | | | | abort the build process, but | |
| | simply skip the extension. | | | | simply skip the extension. | |
+------------------------+--------------------------------+---------------------------+ +------------------------+--------------------------------+---------------------------+
To distribute extension modules that live in a package (e.g. ``package.ext``),
you need to create you need to create a :file:`{package}/__init__.py` file to
let Python recognize and import your module.

View file

@ -177,6 +177,10 @@ resulting object code are identical in both cases; the only difference is where
in the filesystem (and therefore where in Python's namespace hierarchy) the in the filesystem (and therefore where in Python's namespace hierarchy) the
resulting extension lives. resulting extension lives.
If your distribution contains only one or more extension modules in a package,
you need to create a :file:`{package}/__init__.py` file anyway, otherwise Python
won't be able to import anything.
If you have a number of extensions all in the same package (or all under the If you have a number of extensions all in the same package (or all under the
same base package), use the :option:`ext_package` keyword argument to same base package), use the :option:`ext_package` keyword argument to
:func:`setup`. For example, :: :func:`setup`. For example, ::

View file

@ -0,0 +1,78 @@
import os
import tempfile
from packaging.dist import Distribution
from packaging.tests import support, unittest
class TestingSupportTestCase(unittest.TestCase):
def test_fake_dec(self):
@support.fake_dec(1, 2, k=3)
def func(arg0, *args, **kargs):
return arg0, args, kargs
self.assertEqual(func(-1, -2, k=-3), (-1, (-2,), {'k': -3}))
def test_TempdirManager(self):
files = {}
class Tester(support.TempdirManager, unittest.TestCase):
def test_mktempfile(self2):
tmpfile = self2.mktempfile()
files['test_mktempfile'] = tmpfile.name
self.assertTrue(os.path.isfile(tmpfile.name))
def test_mkdtemp(self2):
tmpdir = self2.mkdtemp()
files['test_mkdtemp'] = tmpdir
self.assertTrue(os.path.isdir(tmpdir))
def test_write_file(self2):
tmpdir = self2.mkdtemp()
files['test_write_file'] = tmpdir
self2.write_file((tmpdir, 'file1'), 'me file 1')
file1 = os.path.join(tmpdir, 'file1')
self.assertTrue(os.path.isfile(file1))
text = ''
with open(file1, 'r') as f:
text = f.read()
self.assertEqual(text, 'me file 1')
def test_create_dist(self2):
project_dir, dist = self2.create_dist()
files['test_create_dist'] = project_dir
self.assertTrue(os.path.isdir(project_dir))
self.assertIsInstance(dist, Distribution)
def test_assertIsFile(self2):
fd, fn = tempfile.mkstemp()
os.close(fd)
self.addCleanup(support.unlink, fn)
self2.assertIsFile(fn)
self.assertRaises(AssertionError, self2.assertIsFile, 'foO')
def test_assertIsNotFile(self2):
tmpdir = self2.mkdtemp()
self2.assertIsNotFile(tmpdir)
tester = Tester()
for name in ('test_mktempfile', 'test_mkdtemp', 'test_write_file',
'test_create_dist', 'test_assertIsFile',
'test_assertIsNotFile'):
tester.setUp()
try:
getattr(tester, name)()
finally:
tester.tearDown()
# check clean-up
if name in files:
self.assertFalse(os.path.exists(files[name]))
def test_suite():
return unittest.makeSuite(TestingSupportTestCase)
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")

View file

@ -5,11 +5,10 @@ import time
import logging import logging
import tempfile import tempfile
import textwrap import textwrap
import warnings
import subprocess import subprocess
from io import StringIO from io import StringIO
from packaging.tests import support, unittest
from packaging.tests.test_config import SETUP_CFG
from packaging.errors import ( from packaging.errors import (
PackagingPlatformError, PackagingByteCompileError, PackagingFileError, PackagingPlatformError, PackagingByteCompileError, PackagingFileError,
PackagingExecError, InstallationException) PackagingExecError, InstallationException)
@ -20,7 +19,11 @@ from packaging.util import (
get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages, get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages,
spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob, spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob,
RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging, 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 = """\ PYPIRC = """\
@ -513,7 +516,9 @@ class UtilTestCase(support.EnvironRestorer,
self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8') self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8')
self.write_file('README', 'loooong description') 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 # use Distribution to get the contents of the setup.cfg file
dist = Distribution() dist = Distribution()
dist.parse_config_files() dist.parse_config_files()
@ -539,6 +544,26 @@ class UtilTestCase(support.EnvironRestorer,
self.assertEqual(args['scripts'], dist.scripts) self.assertEqual(args['scripts'], dist.scripts)
self.assertEqual(args['py_modules'], dist.py_modules) 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): def test_encode_multipart(self):
fields = [('username', 'wok'), ('password', 'secret')] fields = [('username', 'wok'), ('password', 'secret')]
files = [('picture', 'wok.png', b'PNG89')] files = [('picture', 'wok.png', b'PNG89')]
@ -590,7 +615,6 @@ class GlobTestCase(GlobTestCaseBase):
super(GlobTestCase, self).tearDown() super(GlobTestCase, self).tearDown()
def assertGlobMatch(self, glob, spec): def assertGlobMatch(self, glob, spec):
""""""
tempdir = self.build_files_tree(spec) tempdir = self.build_files_tree(spec)
expected = self.clean_tree(spec) expected = self.clean_tree(spec)
os.chdir(tempdir) os.chdir(tempdir)

View file

@ -6,6 +6,7 @@ import csv
import imp import imp
import sys import sys
import errno import errno
import codecs
import shutil import shutil
import string import string
import hashlib import hashlib
@ -417,7 +418,8 @@ byte_compile(files, optimize=%r, force=%r,
# cfile - byte-compiled file # cfile - byte-compiled file
# dfile - purported source filename (same as 'file' by default) # dfile - purported source filename (same as 'file' by default)
if optimize >= 0: if optimize >= 0:
cfile = imp.cache_from_source(file, debug_override=not optimize) cfile = imp.cache_from_source(file,
debug_override=not optimize)
else: else:
cfile = imp.cache_from_source(file) cfile = imp.cache_from_source(file)
dfile = file dfile = file
@ -931,6 +933,24 @@ def _iglob(path_glob):
yield file 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'): def cfg_to_args(path='setup.cfg'):
"""Compatibility helper to use setup.cfg in setup.py. """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, *file* is the path to the setup.cfg file. If it doesn't exist,
PackagingFileError is raised. 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 # XXX ** == needs testing
D1_D2_SETUP_ARGS = {"name": ("metadata",), D1_D2_SETUP_ARGS = {"name": ("metadata",),
@ -986,10 +1004,11 @@ def cfg_to_args(path='setup.cfg'):
# The real code starts here # The real code starts here
config = RawConfigParser() config = RawConfigParser()
if not os.path.exists(path): f = codecs.open(path, encoding='utf-8')
raise PackagingFileError("file '%s' does not exist" % try:
os.path.abspath(path)) config.readfp(f)
config.read(path, encoding='utf-8') finally:
f.close()
kwargs = {} kwargs = {}
for arg in D1_D2_SETUP_ARGS: for arg in D1_D2_SETUP_ARGS:
@ -1011,8 +1030,11 @@ def cfg_to_args(path='setup.cfg'):
filenames = split_multiline(filenames) filenames = split_multiline(filenames)
in_cfg_value = [] in_cfg_value = []
for filename in filenames: for filename in filenames:
with open(filename) as fp: fp = codecs.open(filename, encoding='utf-8')
try:
in_cfg_value.append(fp.read()) in_cfg_value.append(fp.read())
finally:
fp.close()
in_cfg_value = '\n\n'.join(in_cfg_value) in_cfg_value = '\n\n'.join(in_cfg_value)
else: else:
continue continue
@ -1029,13 +1051,19 @@ def cfg_to_args(path='setup.cfg'):
return kwargs return kwargs
_SETUP_TMPL = """\ SETUP_TEMPLATE = """\
# This script was automatically generated by packaging # This script was automatically generated by packaging
import os import os
import codecs
from distutils.core import setup 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()) setup(**cfg_to_args())
""" """
@ -1049,8 +1077,10 @@ def generate_setup_py():
if os.path.exists("setup.py"): if os.path.exists("setup.py"):
raise PackagingFileError("a setup.py file already exists") 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: 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 # 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, def copy_tree(src, dst, preserve_mode=True, preserve_times=True,
preserve_symlinks=False, update=False, verbose=True, preserve_symlinks=False, update=False, verbose=True,
dry_run=False): 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 from distutils.file_util import copy_file
if not dry_run and not os.path.isdir(src): if not dry_run and not os.path.isdir(src):

View file

@ -56,6 +56,7 @@ Nicolas Bareil
Chris Barker Chris Barker
Nick Barnes Nick Barnes
Quentin Barnes Quentin Barnes
David Barnett
Richard Barran Richard Barran
Cesar Eduardo Barros Cesar Eduardo Barros
Des Barry Des Barry

View file

@ -505,7 +505,7 @@ Library
in os.kill(). in os.kill().
- Add support for unary plus and unary minus to collections.Counter(). - Add support for unary plus and unary minus to collections.Counter().
Issue #13121: Also an support for inplace math operators. Issue #13121: Also add support for inplace math operators.
- Issue #12683: urlparse updated to include svn as schemes that uses relative - Issue #12683: urlparse updated to include svn as schemes that uses relative
paths. (svn from 1.5 onwards support relative path). paths. (svn from 1.5 onwards support relative path).