Skip to content

Commit 278d975

Browse files
[3.6] bpo-34272: Move argument parsing tests from test_capi to test_getargs2. (GH-8567). (GH-8690)
(cherry picked from commit 8f7bb10)
1 parent ed8dd59 commit 278d975

File tree

2 files changed

+182
-291
lines changed

2 files changed

+182
-291
lines changed

Lib/test/test_capi.py

Lines changed: 3 additions & 290 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import pickle
66
import random
77
import re
8-
import string
98
import subprocess
109
import sys
1110
import sysconfig
@@ -373,289 +372,6 @@ def test_subinterps(self):
373372
self.assertNotEqual(pickle.load(f), id(builtins))
374373

375374

376-
# Bug #6012
377-
class Test6012(unittest.TestCase):
378-
def test(self):
379-
self.assertEqual(_testcapi.argparsing("Hello", "World"), 1)
380-
381-
382-
class EmbeddingTests(unittest.TestCase):
383-
def setUp(self):
384-
here = os.path.abspath(__file__)
385-
basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))
386-
exename = "_testembed"
387-
if sys.platform.startswith("win"):
388-
ext = ("_d" if "_d" in sys.executable else "") + ".exe"
389-
exename += ext
390-
exepath = os.path.dirname(sys.executable)
391-
else:
392-
exepath = os.path.join(basepath, "Programs")
393-
self.test_exe = exe = os.path.join(exepath, exename)
394-
if not os.path.exists(exe):
395-
self.skipTest("%r doesn't exist" % exe)
396-
# This is needed otherwise we get a fatal error:
397-
# "Py_Initialize: Unable to get the locale encoding
398-
# LookupError: no codec search functions registered: can't find encoding"
399-
self.oldcwd = os.getcwd()
400-
os.chdir(basepath)
401-
402-
def tearDown(self):
403-
os.chdir(self.oldcwd)
404-
405-
def run_embedded_interpreter(self, *args, env=None):
406-
"""Runs a test in the embedded interpreter"""
407-
cmd = [self.test_exe]
408-
cmd.extend(args)
409-
if env is not None and sys.platform == 'win32':
410-
# Windows requires at least the SYSTEMROOT environment variable to
411-
# start Python.
412-
env = env.copy()
413-
env['SYSTEMROOT'] = os.environ['SYSTEMROOT']
414-
415-
p = subprocess.Popen(cmd,
416-
stdout=subprocess.PIPE,
417-
stderr=subprocess.PIPE,
418-
universal_newlines=True,
419-
env=env)
420-
(out, err) = p.communicate()
421-
self.assertEqual(p.returncode, 0,
422-
"bad returncode %d, stderr is %r" %
423-
(p.returncode, err))
424-
return out, err
425-
426-
def test_repeated_init_and_subinterpreters(self):
427-
# This is just a "don't crash" test
428-
out, err = self.run_embedded_interpreter('repeated_init_and_subinterpreters')
429-
if support.verbose:
430-
print()
431-
print(out)
432-
print(err)
433-
434-
@staticmethod
435-
def _get_default_pipe_encoding():
436-
rp, wp = os.pipe()
437-
try:
438-
with os.fdopen(wp, 'w') as w:
439-
default_pipe_encoding = w.encoding
440-
finally:
441-
os.close(rp)
442-
return default_pipe_encoding
443-
444-
def test_forced_io_encoding(self):
445-
# Checks forced configuration of embedded interpreter IO streams
446-
env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
447-
out, err = self.run_embedded_interpreter("forced_io_encoding", env=env)
448-
if support.verbose:
449-
print()
450-
print(out)
451-
print(err)
452-
expected_stream_encoding = "utf-8"
453-
expected_errors = "surrogateescape"
454-
expected_pipe_encoding = self._get_default_pipe_encoding()
455-
expected_output = '\n'.join([
456-
"--- Use defaults ---",
457-
"Expected encoding: default",
458-
"Expected errors: default",
459-
"stdin: {in_encoding}:{errors}",
460-
"stdout: {out_encoding}:{errors}",
461-
"stderr: {out_encoding}:backslashreplace",
462-
"--- Set errors only ---",
463-
"Expected encoding: default",
464-
"Expected errors: ignore",
465-
"stdin: {in_encoding}:ignore",
466-
"stdout: {out_encoding}:ignore",
467-
"stderr: {out_encoding}:backslashreplace",
468-
"--- Set encoding only ---",
469-
"Expected encoding: latin-1",
470-
"Expected errors: default",
471-
"stdin: latin-1:{errors}",
472-
"stdout: latin-1:{errors}",
473-
"stderr: latin-1:backslashreplace",
474-
"--- Set encoding and errors ---",
475-
"Expected encoding: latin-1",
476-
"Expected errors: replace",
477-
"stdin: latin-1:replace",
478-
"stdout: latin-1:replace",
479-
"stderr: latin-1:backslashreplace"])
480-
expected_output = expected_output.format(
481-
in_encoding=expected_stream_encoding,
482-
out_encoding=expected_stream_encoding,
483-
errors=expected_errors)
484-
# This is useful if we ever trip over odd platform behaviour
485-
self.maxDiff = None
486-
self.assertEqual(out.strip(), expected_output)
487-
488-
def test_pre_initialization_api(self):
489-
"""
490-
Checks the few parts of the C-API that work before the runtine
491-
is initialized (via Py_Initialize()).
492-
"""
493-
env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
494-
out, err = self.run_embedded_interpreter("pre_initialization_api", env=env)
495-
self.assertEqual(out, '')
496-
self.assertEqual(err, '')
497-
498-
499-
class SkipitemTest(unittest.TestCase):
500-
501-
def test_skipitem(self):
502-
"""
503-
If this test failed, you probably added a new "format unit"
504-
in Python/getargs.c, but neglected to update our poor friend
505-
skipitem() in the same file. (If so, shame on you!)
506-
507-
With a few exceptions**, this function brute-force tests all
508-
printable ASCII*** characters (32 to 126 inclusive) as format units,
509-
checking to see that PyArg_ParseTupleAndKeywords() return consistent
510-
errors both when the unit is attempted to be used and when it is
511-
skipped. If the format unit doesn't exist, we'll get one of two
512-
specific error messages (one for used, one for skipped); if it does
513-
exist we *won't* get that error--we'll get either no error or some
514-
other error. If we get the specific "does not exist" error for one
515-
test and not for the other, there's a mismatch, and the test fails.
516-
517-
** Some format units have special funny semantics and it would
518-
be difficult to accommodate them here. Since these are all
519-
well-established and properly skipped in skipitem() we can
520-
get away with not testing them--this test is really intended
521-
to catch *new* format units.
522-
523-
*** Python C source files must be ASCII. Therefore it's impossible
524-
to have non-ASCII format units.
525-
526-
"""
527-
empty_tuple = ()
528-
tuple_1 = (0,)
529-
dict_b = {'b':1}
530-
keywords = ["a", "b"]
531-
532-
for i in range(32, 127):
533-
c = chr(i)
534-
535-
# skip parentheses, the error reporting is inconsistent about them
536-
# skip 'e', it's always a two-character code
537-
# skip '|' and '$', they don't represent arguments anyway
538-
if c in '()e|$':
539-
continue
540-
541-
# test the format unit when not skipped
542-
format = c + "i"
543-
try:
544-
_testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
545-
format, keywords)
546-
when_not_skipped = False
547-
except SystemError as e:
548-
s = "argument 1 (impossible<bad format char>)"
549-
when_not_skipped = (str(e) == s)
550-
except TypeError:
551-
when_not_skipped = False
552-
553-
# test the format unit when skipped
554-
optional_format = "|" + format
555-
try:
556-
_testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
557-
optional_format, keywords)
558-
when_skipped = False
559-
except SystemError as e:
560-
s = "impossible<bad format char>: '{}'".format(format)
561-
when_skipped = (str(e) == s)
562-
563-
message = ("test_skipitem_parity: "
564-
"detected mismatch between convertsimple and skipitem "
565-
"for format unit '{}' ({}), not skipped {}, skipped {}".format(
566-
c, i, when_skipped, when_not_skipped))
567-
self.assertIs(when_skipped, when_not_skipped, message)
568-
569-
def test_skipitem_with_suffix(self):
570-
parse = _testcapi.parse_tuple_and_keywords
571-
empty_tuple = ()
572-
tuple_1 = (0,)
573-
dict_b = {'b':1}
574-
keywords = ["a", "b"]
575-
576-
supported = ('s#', 's*', 'z#', 'z*', 'u#', 'Z#', 'y#', 'y*', 'w#', 'w*')
577-
for c in string.ascii_letters:
578-
for c2 in '#*':
579-
f = c + c2
580-
with self.subTest(format=f):
581-
optional_format = "|" + f + "i"
582-
if f in supported:
583-
parse(empty_tuple, dict_b, optional_format, keywords)
584-
else:
585-
with self.assertRaisesRegex(SystemError,
586-
'impossible<bad format char>'):
587-
parse(empty_tuple, dict_b, optional_format, keywords)
588-
589-
for c in map(chr, range(32, 128)):
590-
f = 'e' + c
591-
optional_format = "|" + f + "i"
592-
with self.subTest(format=f):
593-
if c in 'st':
594-
parse(empty_tuple, dict_b, optional_format, keywords)
595-
else:
596-
with self.assertRaisesRegex(SystemError,
597-
'impossible<bad format char>'):
598-
parse(empty_tuple, dict_b, optional_format, keywords)
599-
600-
def test_parse_tuple_and_keywords(self):
601-
# Test handling errors in the parse_tuple_and_keywords helper itself
602-
self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
603-
(), {}, 42, [])
604-
self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
605-
(), {}, '', 42)
606-
self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
607-
(), {}, '', [''] * 42)
608-
self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
609-
(), {}, '', [42])
610-
611-
def test_bad_use(self):
612-
# Test handling invalid format and keywords in
613-
# PyArg_ParseTupleAndKeywords()
614-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
615-
(1,), {}, '||O', ['a'])
616-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
617-
(1, 2), {}, '|O|O', ['a', 'b'])
618-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
619-
(), {'a': 1}, '$$O', ['a'])
620-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
621-
(), {'a': 1, 'b': 2}, '$O$O', ['a', 'b'])
622-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
623-
(), {'a': 1}, '$|O', ['a'])
624-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
625-
(), {'a': 1, 'b': 2}, '$O|O', ['a', 'b'])
626-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
627-
(1,), {}, '|O', ['a', 'b'])
628-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
629-
(1,), {}, '|OO', ['a'])
630-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
631-
(), {}, '|$O', [''])
632-
self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
633-
(), {}, '|OO', ['a', ''])
634-
635-
def test_positional_only(self):
636-
parse = _testcapi.parse_tuple_and_keywords
637-
638-
parse((1, 2, 3), {}, 'OOO', ['', '', 'a'])
639-
parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a'])
640-
with self.assertRaisesRegex(TypeError,
641-
r'Function takes at least 2 positional arguments \(1 given\)'):
642-
parse((1,), {'a': 3}, 'OOO', ['', '', 'a'])
643-
parse((1,), {}, 'O|OO', ['', '', 'a'])
644-
with self.assertRaisesRegex(TypeError,
645-
r'Function takes at least 1 positional arguments \(0 given\)'):
646-
parse((), {}, 'O|OO', ['', '', 'a'])
647-
parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a'])
648-
with self.assertRaisesRegex(TypeError,
649-
r'Function takes exactly 2 positional arguments \(1 given\)'):
650-
parse((1,), {'a': 3}, 'OO$O', ['', '', 'a'])
651-
parse((1,), {}, 'O|O$O', ['', '', 'a'])
652-
with self.assertRaisesRegex(TypeError,
653-
r'Function takes at least 1 positional arguments \(0 given\)'):
654-
parse((), {}, 'O|O$O', ['', '', 'a'])
655-
with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'):
656-
parse((1,), {}, 'O|$OO', ['', '', 'a'])
657-
with self.assertRaisesRegex(SystemError, 'Empty keyword'):
658-
parse((1,), {}, 'O|OO', ['', 'a', ''])
659375

660376

661377
@unittest.skipUnless(threading, 'Threading required for this test.')
@@ -684,12 +400,9 @@ def callback():
684400

685401

686402
class Test_testcapi(unittest.TestCase):
687-
def test__testcapi(self):
688-
for name in dir(_testcapi):
689-
if name.startswith('test_'):
690-
with self.subTest("internal", name=name):
691-
test = getattr(_testcapi, name)
692-
test()
403+
locals().update((name, getattr(_testcapi, name))
404+
for name in dir(_testcapi)
405+
if name.startswith('test_') and not name.endswith('_code'))
693406

694407

695408
class PyMemDebugTests(unittest.TestCase):

0 commit comments

Comments
 (0)