Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3764a96

Browse files
committed
Banch merge
2 parents 04d5bc0 + 89d3a69 commit 3764a96

7 files changed

Lines changed: 161 additions & 18 deletions

File tree

Doc/library/packaging.compiler.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,3 +675,7 @@ extension modules.
675675
| | abort the build process, but | |
676676
| | simply skip the extension. | |
677677
+------------------------+--------------------------------+---------------------------+
678+
679+
To distribute extension modules that live in a package (e.g. ``package.ext``),
680+
you need to create you need to create a :file:`{package}/__init__.py` file to
681+
let Python recognize and import your module.

Doc/packaging/setupscript.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ resulting object code are identical in both cases; the only difference is where
177177
in the filesystem (and therefore where in Python's namespace hierarchy) the
178178
resulting extension lives.
179179

180+
If your distribution contains only one or more extension modules in a package,
181+
you need to create a :file:`{package}/__init__.py` file anyway, otherwise Python
182+
won't be able to import anything.
183+
180184
If you have a number of extensions all in the same package (or all under the
181185
same base package), use the :option:`ext_package` keyword argument to
182186
:func:`setup`. For example, ::
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import os
2+
import tempfile
3+
4+
from packaging.dist import Distribution
5+
from packaging.tests import support, unittest
6+
7+
8+
class TestingSupportTestCase(unittest.TestCase):
9+
10+
def test_fake_dec(self):
11+
@support.fake_dec(1, 2, k=3)
12+
def func(arg0, *args, **kargs):
13+
return arg0, args, kargs
14+
self.assertEqual(func(-1, -2, k=-3), (-1, (-2,), {'k': -3}))
15+
16+
def test_TempdirManager(self):
17+
files = {}
18+
19+
class Tester(support.TempdirManager, unittest.TestCase):
20+
21+
def test_mktempfile(self2):
22+
tmpfile = self2.mktempfile()
23+
files['test_mktempfile'] = tmpfile.name
24+
self.assertTrue(os.path.isfile(tmpfile.name))
25+
26+
def test_mkdtemp(self2):
27+
tmpdir = self2.mkdtemp()
28+
files['test_mkdtemp'] = tmpdir
29+
self.assertTrue(os.path.isdir(tmpdir))
30+
31+
def test_write_file(self2):
32+
tmpdir = self2.mkdtemp()
33+
files['test_write_file'] = tmpdir
34+
self2.write_file((tmpdir, 'file1'), 'me file 1')
35+
file1 = os.path.join(tmpdir, 'file1')
36+
self.assertTrue(os.path.isfile(file1))
37+
text = ''
38+
with open(file1, 'r') as f:
39+
text = f.read()
40+
self.assertEqual(text, 'me file 1')
41+
42+
def test_create_dist(self2):
43+
project_dir, dist = self2.create_dist()
44+
files['test_create_dist'] = project_dir
45+
self.assertTrue(os.path.isdir(project_dir))
46+
self.assertIsInstance(dist, Distribution)
47+
48+
def test_assertIsFile(self2):
49+
fd, fn = tempfile.mkstemp()
50+
os.close(fd)
51+
self.addCleanup(support.unlink, fn)
52+
self2.assertIsFile(fn)
53+
self.assertRaises(AssertionError, self2.assertIsFile, 'foO')
54+
55+
def test_assertIsNotFile(self2):
56+
tmpdir = self2.mkdtemp()
57+
self2.assertIsNotFile(tmpdir)
58+
59+
tester = Tester()
60+
for name in ('test_mktempfile', 'test_mkdtemp', 'test_write_file',
61+
'test_create_dist', 'test_assertIsFile',
62+
'test_assertIsNotFile'):
63+
tester.setUp()
64+
try:
65+
getattr(tester, name)()
66+
finally:
67+
tester.tearDown()
68+
69+
# check clean-up
70+
if name in files:
71+
self.assertFalse(os.path.exists(files[name]))
72+
73+
74+
def test_suite():
75+
return unittest.makeSuite(TestingSupportTestCase)
76+
77+
if __name__ == "__main__":
78+
unittest.main(defaultTest="test_suite")

Lib/packaging/tests/test_util.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
import logging
66
import tempfile
77
import textwrap
8+
import warnings
89
import subprocess
910
from io import StringIO
1011

11-
from packaging.tests import support, unittest
12-
from packaging.tests.test_config import SETUP_CFG
1312
from packaging.errors import (
1413
PackagingPlatformError, PackagingByteCompileError, PackagingFileError,
1514
PackagingExecError, InstallationException)
@@ -20,7 +19,11 @@
2019
get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages,
2120
spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob,
2221
RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging,
23-
get_install_method, cfg_to_args, encode_multipart)
22+
get_install_method, cfg_to_args, generate_setup_py, encode_multipart)
23+
24+
from packaging.tests import support, unittest
25+
from packaging.tests.test_config import SETUP_CFG
26+
from test.script_helper import assert_python_ok, assert_python_failure
2427

2528

2629
PYPIRC = """\
@@ -513,7 +516,9 @@ def test_cfg_to_args(self):
513516
self.write_file('setup.cfg', SETUP_CFG % opts, encoding='utf-8')
514517
self.write_file('README', 'loooong description')
515518

516-
args = cfg_to_args()
519+
with warnings.catch_warnings():
520+
warnings.simplefilter('ignore', DeprecationWarning)
521+
args = cfg_to_args()
517522
# use Distribution to get the contents of the setup.cfg file
518523
dist = Distribution()
519524
dist.parse_config_files()
@@ -539,6 +544,26 @@ def test_cfg_to_args(self):
539544
self.assertEqual(args['scripts'], dist.scripts)
540545
self.assertEqual(args['py_modules'], dist.py_modules)
541546

547+
def test_generate_setup_py(self):
548+
# undo subprocess.Popen monkey-patching before using assert_python_*
549+
subprocess.Popen = self.old_popen
550+
os.chdir(self.mkdtemp())
551+
self.write_file('setup.cfg', textwrap.dedent("""\
552+
[metadata]
553+
name = SPAM
554+
classifier = Programming Language :: Python
555+
"""))
556+
generate_setup_py()
557+
self.assertTrue(os.path.exists('setup.py'), 'setup.py not created')
558+
rc, out, err = assert_python_ok('setup.py', '--name')
559+
self.assertEqual(out, b'SPAM\n')
560+
self.assertEqual(err, b'')
561+
562+
# a generated setup.py should complain if no setup.cfg is present
563+
os.unlink('setup.cfg')
564+
rc, out, err = assert_python_failure('setup.py', '--name')
565+
self.assertIn(b'setup.cfg', err)
566+
542567
def test_encode_multipart(self):
543568
fields = [('username', 'wok'), ('password', 'secret')]
544569
files = [('picture', 'wok.png', b'PNG89')]
@@ -590,7 +615,6 @@ def tearDown(self):
590615
super(GlobTestCase, self).tearDown()
591616

592617
def assertGlobMatch(self, glob, spec):
593-
""""""
594618
tempdir = self.build_files_tree(spec)
595619
expected = self.clean_tree(spec)
596620
os.chdir(tempdir)

Lib/packaging/util.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import imp
77
import sys
88
import errno
9+
import codecs
910
import shutil
1011
import string
1112
import hashlib
@@ -417,7 +418,8 @@ def byte_compile(py_files, optimize=0, force=False, prefix=None,
417418
# cfile - byte-compiled file
418419
# dfile - purported source filename (same as 'file' by default)
419420
if optimize >= 0:
420-
cfile = imp.cache_from_source(file, debug_override=not optimize)
421+
cfile = imp.cache_from_source(file,
422+
debug_override=not optimize)
421423
else:
422424
cfile = imp.cache_from_source(file)
423425
dfile = file
@@ -931,6 +933,24 @@ def _iglob(path_glob):
931933
yield file
932934

933935

936+
# HOWTO change cfg_to_args
937+
#
938+
# This function has two major constraints: It is copied by inspect.getsource
939+
# in generate_setup_py; it is used in generated setup.py which may be run by
940+
# any Python version supported by distutils2 (2.4-3.3).
941+
#
942+
# * Keep objects like D1_D2_SETUP_ARGS static, i.e. in the function body
943+
# instead of global.
944+
# * If you use a function from another module, update the imports in
945+
# SETUP_TEMPLATE. Use only modules, classes and functions compatible with
946+
# all versions: codecs.open instead of open, RawConfigParser.readfp instead
947+
# of read, standard exceptions instead of Packaging*Error, etc.
948+
# * If you use a function from this module, update the template and
949+
# generate_setup_py.
950+
#
951+
# test_util tests this function and the generated setup.py, but does not test
952+
# that it's compatible with all Python versions.
953+
934954
def cfg_to_args(path='setup.cfg'):
935955
"""Compatibility helper to use setup.cfg in setup.py.
936956
@@ -941,8 +961,6 @@ def cfg_to_args(path='setup.cfg'):
941961
*file* is the path to the setup.cfg file. If it doesn't exist,
942962
PackagingFileError is raised.
943963
"""
944-
# We need to declare the following constants here so that it's easier to
945-
# generate the setup.py afterwards, using inspect.getsource.
946964

947965
# XXX ** == needs testing
948966
D1_D2_SETUP_ARGS = {"name": ("metadata",),
@@ -986,10 +1004,11 @@ def has_get_option(config, section, option):
9861004

9871005
# The real code starts here
9881006
config = RawConfigParser()
989-
if not os.path.exists(path):
990-
raise PackagingFileError("file '%s' does not exist" %
991-
os.path.abspath(path))
992-
config.read(path, encoding='utf-8')
1007+
f = codecs.open(path, encoding='utf-8')
1008+
try:
1009+
config.readfp(f)
1010+
finally:
1011+
f.close()
9931012

9941013
kwargs = {}
9951014
for arg in D1_D2_SETUP_ARGS:
@@ -1011,8 +1030,11 @@ def has_get_option(config, section, option):
10111030
filenames = split_multiline(filenames)
10121031
in_cfg_value = []
10131032
for filename in filenames:
1014-
with open(filename) as fp:
1033+
fp = codecs.open(filename, encoding='utf-8')
1034+
try:
10151035
in_cfg_value.append(fp.read())
1036+
finally:
1037+
fp.close()
10161038
in_cfg_value = '\n\n'.join(in_cfg_value)
10171039
else:
10181040
continue
@@ -1029,13 +1051,19 @@ def has_get_option(config, section, option):
10291051
return kwargs
10301052

10311053

1032-
_SETUP_TMPL = """\
1054+
SETUP_TEMPLATE = """\
10331055
# This script was automatically generated by packaging
10341056
import os
1057+
import codecs
10351058
from distutils.core import setup
1036-
from ConfigParser import RawConfigParser
1059+
try:
1060+
from ConfigParser import RawConfigParser
1061+
except ImportError:
1062+
from configparser import RawConfigParser
1063+
1064+
%(split_multiline)s
10371065
1038-
%(func)s
1066+
%(cfg_to_args)s
10391067
10401068
setup(**cfg_to_args())
10411069
"""
@@ -1049,8 +1077,10 @@ def generate_setup_py():
10491077
if os.path.exists("setup.py"):
10501078
raise PackagingFileError("a setup.py file already exists")
10511079

1080+
source = SETUP_TEMPLATE % {'split_multiline': getsource(split_multiline),
1081+
'cfg_to_args': getsource(cfg_to_args)}
10521082
with open("setup.py", "w", encoding='utf-8') as fp:
1053-
fp.write(_SETUP_TMPL % {'func': getsource(cfg_to_args)})
1083+
fp.write(source)
10541084

10551085

10561086
# Taken from the pip project
@@ -1307,6 +1337,8 @@ def get_install_method(path):
13071337
def copy_tree(src, dst, preserve_mode=True, preserve_times=True,
13081338
preserve_symlinks=False, update=False, verbose=True,
13091339
dry_run=False):
1340+
# FIXME use of this function is why we get spurious logging message on
1341+
# stdout when tests run; kill and replace by shuil!
13101342
from distutils.file_util import copy_file
13111343

13121344
if not dry_run and not os.path.isdir(src):

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Nicolas Bareil
5656
Chris Barker
5757
Nick Barnes
5858
Quentin Barnes
59+
David Barnett
5960
Richard Barran
6061
Cesar Eduardo Barros
6162
Des Barry

Misc/NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ Library
505505
in os.kill().
506506

507507
- Add support for unary plus and unary minus to collections.Counter().
508-
Issue #13121: Also an support for inplace math operators.
508+
Issue #13121: Also add support for inplace math operators.
509509

510510
- Issue #12683: urlparse updated to include svn as schemes that uses relative
511511
paths. (svn from 1.5 onwards support relative path).

0 commit comments

Comments
 (0)