mirror of
https://github.com/python/cpython.git
synced 2025-10-03 13:45:29 +00:00
(cherry picked from commit 3ee8dac7a1
)
This commit is contained in:
parent
67127ca8e2
commit
38fe0e7c2d
1 changed files with 436 additions and 352 deletions
|
@ -3,7 +3,8 @@
|
||||||
# Licensed to the PSF under a contributor agreement.
|
# Licensed to the PSF under a contributor agreement.
|
||||||
|
|
||||||
from test import support, test_tools
|
from test import support, test_tools
|
||||||
from test.support import import_helper, os_helper
|
from test.support import os_helper
|
||||||
|
from textwrap import dedent
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
import collections
|
import collections
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -242,7 +243,7 @@ class ClinicBlockParserTest(TestCase):
|
||||||
self.round_trip("""
|
self.round_trip("""
|
||||||
verbatim text here
|
verbatim text here
|
||||||
lah dee dah
|
lah dee dah
|
||||||
""")
|
""")
|
||||||
def test_round_trip_2(self):
|
def test_round_trip_2(self):
|
||||||
self.round_trip("""
|
self.round_trip("""
|
||||||
verbatim text here
|
verbatim text here
|
||||||
|
@ -286,22 +287,38 @@ xyz
|
||||||
|
|
||||||
|
|
||||||
class ClinicParserTest(TestCase):
|
class ClinicParserTest(TestCase):
|
||||||
|
def checkDocstring(self, fn, expected):
|
||||||
|
self.assertTrue(hasattr(fn, "docstring"))
|
||||||
|
self.assertEqual(fn.docstring.strip(),
|
||||||
|
dedent(expected).strip())
|
||||||
|
|
||||||
def test_trivial(self):
|
def test_trivial(self):
|
||||||
parser = DSLParser(FakeClinic())
|
parser = DSLParser(FakeClinic())
|
||||||
block = clinic.Block("module os\nos.access")
|
block = clinic.Block("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
""")
|
||||||
parser.parse(block)
|
parser.parse(block)
|
||||||
module, function = block.signatures
|
module, function = block.signatures
|
||||||
self.assertEqual("access", function.name)
|
self.assertEqual("access", function.name)
|
||||||
self.assertEqual("os", module.name)
|
self.assertEqual("os", module.name)
|
||||||
|
|
||||||
def test_ignore_line(self):
|
def test_ignore_line(self):
|
||||||
block = self.parse("#\nmodule os\nos.access")
|
block = self.parse(dedent("""
|
||||||
|
#
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
"""))
|
||||||
module, function = block.signatures
|
module, function = block.signatures
|
||||||
self.assertEqual("access", function.name)
|
self.assertEqual("access", function.name)
|
||||||
self.assertEqual("os", module.name)
|
self.assertEqual("os", module.name)
|
||||||
|
|
||||||
def test_param(self):
|
def test_param(self):
|
||||||
function = self.parse_function("module os\nos.access\n path: int")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
path: int
|
||||||
|
""")
|
||||||
self.assertEqual("access", function.name)
|
self.assertEqual("access", function.name)
|
||||||
self.assertEqual(2, len(function.parameters))
|
self.assertEqual(2, len(function.parameters))
|
||||||
p = function.parameters['path']
|
p = function.parameters['path']
|
||||||
|
@ -309,125 +326,181 @@ class ClinicParserTest(TestCase):
|
||||||
self.assertIsInstance(p.converter, clinic.int_converter)
|
self.assertIsInstance(p.converter, clinic.int_converter)
|
||||||
|
|
||||||
def test_param_default(self):
|
def test_param_default(self):
|
||||||
function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
follow_symlinks: bool = True
|
||||||
|
""")
|
||||||
p = function.parameters['follow_symlinks']
|
p = function.parameters['follow_symlinks']
|
||||||
self.assertEqual(True, p.default)
|
self.assertEqual(True, p.default)
|
||||||
|
|
||||||
def test_param_with_continuations(self):
|
def test_param_with_continuations(self):
|
||||||
function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True")
|
function = self.parse_function(r"""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
follow_symlinks: \
|
||||||
|
bool \
|
||||||
|
= \
|
||||||
|
True
|
||||||
|
""")
|
||||||
p = function.parameters['follow_symlinks']
|
p = function.parameters['follow_symlinks']
|
||||||
self.assertEqual(True, p.default)
|
self.assertEqual(True, p.default)
|
||||||
|
|
||||||
def test_param_default_expression(self):
|
def test_param_default_expression(self):
|
||||||
function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize
|
||||||
|
""")
|
||||||
p = function.parameters['follow_symlinks']
|
p = function.parameters['follow_symlinks']
|
||||||
self.assertEqual(sys.maxsize, p.default)
|
self.assertEqual(sys.maxsize, p.default)
|
||||||
self.assertEqual("MAXSIZE", p.converter.c_default)
|
self.assertEqual("MAXSIZE", p.converter.c_default)
|
||||||
|
|
||||||
s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize")
|
expected_msg = (
|
||||||
self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n")
|
"Error on line 0:\n"
|
||||||
|
"When you specify a named constant ('sys.maxsize') as your default value,\n"
|
||||||
|
"you MUST specify a valid c_default.\n"
|
||||||
|
)
|
||||||
|
out = self.parse_function_should_fail("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
follow_symlinks: int = sys.maxsize
|
||||||
|
""")
|
||||||
|
self.assertEqual(out, expected_msg)
|
||||||
|
|
||||||
def test_param_no_docstring(self):
|
def test_param_no_docstring(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
module os
|
module os
|
||||||
os.access
|
os.access
|
||||||
follow_symlinks: bool = True
|
follow_symlinks: bool = True
|
||||||
something_else: str = ''""")
|
something_else: str = ''
|
||||||
|
""")
|
||||||
p = function.parameters['follow_symlinks']
|
p = function.parameters['follow_symlinks']
|
||||||
self.assertEqual(3, len(function.parameters))
|
self.assertEqual(3, len(function.parameters))
|
||||||
self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter)
|
conv = function.parameters['something_else'].converter
|
||||||
|
self.assertIsInstance(conv, clinic.str_converter)
|
||||||
|
|
||||||
def test_param_default_parameters_out_of_order(self):
|
def test_param_default_parameters_out_of_order(self):
|
||||||
s = self.parse_function_should_fail("""
|
expected_msg = (
|
||||||
module os
|
"Error on line 0:\n"
|
||||||
os.access
|
"Can't have a parameter without a default ('something_else')\n"
|
||||||
|
"after a parameter with a default!\n"
|
||||||
|
)
|
||||||
|
out = self.parse_function_should_fail("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
follow_symlinks: bool = True
|
follow_symlinks: bool = True
|
||||||
something_else: str""")
|
something_else: str""")
|
||||||
self.assertEqual(s, """Error on line 0:
|
self.assertEqual(out, expected_msg)
|
||||||
Can't have a parameter without a default ('something_else')
|
|
||||||
after a parameter with a default!
|
|
||||||
""")
|
|
||||||
|
|
||||||
def disabled_test_converter_arguments(self):
|
def disabled_test_converter_arguments(self):
|
||||||
function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
path: path_t(allow_fd=1)
|
||||||
|
""")
|
||||||
p = function.parameters['path']
|
p = function.parameters['path']
|
||||||
self.assertEqual(1, p.converter.args['allow_fd'])
|
self.assertEqual(1, p.converter.args['allow_fd'])
|
||||||
|
|
||||||
def test_function_docstring(self):
|
def test_function_docstring(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
module os
|
module os
|
||||||
os.stat as os_stat_fn
|
os.stat as os_stat_fn
|
||||||
|
|
||||||
path: str
|
path: str
|
||||||
Path to be examined
|
Path to be examined
|
||||||
|
|
||||||
Perform a stat system call on the given path.""")
|
Perform a stat system call on the given path.
|
||||||
self.assertEqual("""
|
""")
|
||||||
stat($module, /, path)
|
self.checkDocstring(function, """
|
||||||
--
|
stat($module, /, path)
|
||||||
|
--
|
||||||
|
|
||||||
Perform a stat system call on the given path.
|
Perform a stat system call on the given path.
|
||||||
|
|
||||||
path
|
path
|
||||||
Path to be examined
|
Path to be examined
|
||||||
""".strip(), function.docstring)
|
""")
|
||||||
|
|
||||||
def test_explicit_parameters_in_docstring(self):
|
def test_explicit_parameters_in_docstring(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function(dedent("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
x: int
|
x: int
|
||||||
Documentation for x.
|
Documentation for x.
|
||||||
y: int
|
y: int
|
||||||
|
|
||||||
This is the documentation for foo.
|
This is the documentation for foo.
|
||||||
|
|
||||||
Okay, we're done here.
|
Okay, we're done here.
|
||||||
""")
|
"""))
|
||||||
self.assertEqual("""
|
self.checkDocstring(function, """
|
||||||
bar($module, /, x, y)
|
bar($module, /, x, y)
|
||||||
--
|
--
|
||||||
|
|
||||||
This is the documentation for foo.
|
This is the documentation for foo.
|
||||||
|
|
||||||
x
|
x
|
||||||
Documentation for x.
|
Documentation for x.
|
||||||
|
|
||||||
Okay, we're done here.
|
Okay, we're done here.
|
||||||
""".strip(), function.docstring)
|
""")
|
||||||
|
|
||||||
def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
|
def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function(dedent("""
|
||||||
module os
|
module os
|
||||||
os.stat
|
os.stat
|
||||||
path: str
|
path: str
|
||||||
This/used to break Clinic!
|
This/used to break Clinic!
|
||||||
""")
|
"""))
|
||||||
self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring)
|
self.checkDocstring(function, """
|
||||||
|
stat($module, /, path)
|
||||||
|
--
|
||||||
|
|
||||||
|
This/used to break Clinic!
|
||||||
|
""")
|
||||||
|
|
||||||
def test_c_name(self):
|
def test_c_name(self):
|
||||||
function = self.parse_function("module os\nos.stat as os_stat_fn")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.stat as os_stat_fn
|
||||||
|
""")
|
||||||
self.assertEqual("os_stat_fn", function.c_basename)
|
self.assertEqual("os_stat_fn", function.c_basename)
|
||||||
|
|
||||||
def test_return_converter(self):
|
def test_return_converter(self):
|
||||||
function = self.parse_function("module os\nos.stat -> int")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.stat -> int
|
||||||
|
""")
|
||||||
self.assertIsInstance(function.return_converter, clinic.int_return_converter)
|
self.assertIsInstance(function.return_converter, clinic.int_return_converter)
|
||||||
|
|
||||||
def test_star(self):
|
def test_star(self):
|
||||||
function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True")
|
function = self.parse_function("""
|
||||||
|
module os
|
||||||
|
os.access
|
||||||
|
*
|
||||||
|
follow_symlinks: bool = True
|
||||||
|
""")
|
||||||
p = function.parameters['follow_symlinks']
|
p = function.parameters['follow_symlinks']
|
||||||
self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
|
self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
|
||||||
self.assertEqual(0, p.group)
|
self.assertEqual(0, p.group)
|
||||||
|
|
||||||
def test_group(self):
|
def test_group(self):
|
||||||
function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n")
|
function = self.parse_function("""
|
||||||
|
module window
|
||||||
|
window.border
|
||||||
|
[
|
||||||
|
ls: int
|
||||||
|
]
|
||||||
|
/
|
||||||
|
""")
|
||||||
p = function.parameters['ls']
|
p = function.parameters['ls']
|
||||||
self.assertEqual(1, p.group)
|
self.assertEqual(1, p.group)
|
||||||
|
|
||||||
def test_left_group(self):
|
def test_left_group(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
module curses
|
module curses
|
||||||
curses.addch
|
curses.addch
|
||||||
[
|
[
|
||||||
y: int
|
y: int
|
||||||
Y-coordinate.
|
Y-coordinate.
|
||||||
|
@ -441,17 +514,19 @@ curses.addch
|
||||||
Attributes for the character.
|
Attributes for the character.
|
||||||
]
|
]
|
||||||
/
|
/
|
||||||
""")
|
""")
|
||||||
for name, group in (
|
dataset = (
|
||||||
('y', -1), ('x', -1),
|
('y', -1), ('x', -1),
|
||||||
('ch', 0),
|
('ch', 0),
|
||||||
('attr', 1),
|
('attr', 1),
|
||||||
):
|
)
|
||||||
|
for name, group in dataset:
|
||||||
|
with self.subTest(name=name, group=group):
|
||||||
p = function.parameters[name]
|
p = function.parameters[name]
|
||||||
self.assertEqual(p.group, group)
|
self.assertEqual(p.group, group)
|
||||||
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
||||||
self.assertEqual(function.docstring.strip(), """
|
self.checkDocstring(function, """
|
||||||
addch([y, x,] ch, [attr])
|
addch([y, x,] ch, [attr])
|
||||||
|
|
||||||
|
|
||||||
y
|
y
|
||||||
|
@ -462,12 +537,12 @@ addch([y, x,] ch, [attr])
|
||||||
Character to add.
|
Character to add.
|
||||||
attr
|
attr
|
||||||
Attributes for the character.
|
Attributes for the character.
|
||||||
""".strip())
|
""")
|
||||||
|
|
||||||
def test_nested_groups(self):
|
def test_nested_groups(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
module curses
|
module curses
|
||||||
curses.imaginary
|
curses.imaginary
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
y1: int
|
y1: int
|
||||||
|
@ -499,20 +574,22 @@ curses.imaginary
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
/
|
/
|
||||||
""")
|
""")
|
||||||
for name, group in (
|
dataset = (
|
||||||
('y1', -2), ('y2', -2),
|
('y1', -2), ('y2', -2),
|
||||||
('x1', -1), ('x2', -1),
|
('x1', -1), ('x2', -1),
|
||||||
('ch', 0),
|
('ch', 0),
|
||||||
('attr1', 1), ('attr2', 1), ('attr3', 1),
|
('attr1', 1), ('attr2', 1), ('attr3', 1),
|
||||||
('attr4', 2), ('attr5', 2), ('attr6', 2),
|
('attr4', 2), ('attr5', 2), ('attr6', 2),
|
||||||
):
|
)
|
||||||
|
for name, group in dataset:
|
||||||
|
with self.subTest(name=name, group=group):
|
||||||
p = function.parameters[name]
|
p = function.parameters[name]
|
||||||
self.assertEqual(p.group, group)
|
self.assertEqual(p.group, group)
|
||||||
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
||||||
|
|
||||||
self.assertEqual(function.docstring.strip(), """
|
self.checkDocstring(function, """
|
||||||
imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
|
imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
|
||||||
attr6]])
|
attr6]])
|
||||||
|
|
||||||
|
|
||||||
|
@ -538,7 +615,7 @@ imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
|
||||||
Attributes for the character.
|
Attributes for the character.
|
||||||
attr6
|
attr6
|
||||||
Attributes for the character.
|
Attributes for the character.
|
||||||
""".strip())
|
""")
|
||||||
|
|
||||||
def parse_function_should_fail(self, s):
|
def parse_function_should_fail(self, s):
|
||||||
with support.captured_stdout() as stdout:
|
with support.captured_stdout() as stdout:
|
||||||
|
@ -547,9 +624,14 @@ imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
|
||||||
return stdout.getvalue()
|
return stdout.getvalue()
|
||||||
|
|
||||||
def test_disallowed_grouping__two_top_groups_on_left(self):
|
def test_disallowed_grouping__two_top_groups_on_left(self):
|
||||||
s = self.parse_function_should_fail("""
|
expected_msg = (
|
||||||
module foo
|
'Error on line 0:\n'
|
||||||
foo.two_top_groups_on_left
|
'Function two_top_groups_on_left has an unsupported group '
|
||||||
|
'configuration. (Unexpected state 2.b)\n'
|
||||||
|
)
|
||||||
|
out = self.parse_function_should_fail("""
|
||||||
|
module foo
|
||||||
|
foo.two_top_groups_on_left
|
||||||
[
|
[
|
||||||
group1 : int
|
group1 : int
|
||||||
]
|
]
|
||||||
|
@ -558,14 +640,12 @@ foo.two_top_groups_on_left
|
||||||
]
|
]
|
||||||
param: int
|
param: int
|
||||||
""")
|
""")
|
||||||
self.assertEqual(s,
|
self.assertEqual(out, expected_msg)
|
||||||
('Error on line 0:\n'
|
|
||||||
'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n'))
|
|
||||||
|
|
||||||
def test_disallowed_grouping__two_top_groups_on_right(self):
|
def test_disallowed_grouping__two_top_groups_on_right(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.two_top_groups_on_right
|
foo.two_top_groups_on_right
|
||||||
param: int
|
param: int
|
||||||
[
|
[
|
||||||
group1 : int
|
group1 : int
|
||||||
|
@ -577,8 +657,8 @@ foo.two_top_groups_on_right
|
||||||
|
|
||||||
def test_disallowed_grouping__parameter_after_group_on_right(self):
|
def test_disallowed_grouping__parameter_after_group_on_right(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.parameter_after_group_on_right
|
foo.parameter_after_group_on_right
|
||||||
param: int
|
param: int
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
|
@ -590,8 +670,8 @@ foo.parameter_after_group_on_right
|
||||||
|
|
||||||
def test_disallowed_grouping__group_after_parameter_on_left(self):
|
def test_disallowed_grouping__group_after_parameter_on_left(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.group_after_parameter_on_left
|
foo.group_after_parameter_on_left
|
||||||
[
|
[
|
||||||
group2 : int
|
group2 : int
|
||||||
[
|
[
|
||||||
|
@ -603,8 +683,8 @@ foo.group_after_parameter_on_left
|
||||||
|
|
||||||
def test_disallowed_grouping__empty_group_on_left(self):
|
def test_disallowed_grouping__empty_group_on_left(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.empty_group
|
foo.empty_group
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
]
|
]
|
||||||
|
@ -615,8 +695,8 @@ foo.empty_group
|
||||||
|
|
||||||
def test_disallowed_grouping__empty_group_on_right(self):
|
def test_disallowed_grouping__empty_group_on_right(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.empty_group
|
foo.empty_group
|
||||||
param: int
|
param: int
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
|
@ -627,24 +707,25 @@ foo.empty_group
|
||||||
|
|
||||||
def test_no_parameters(self):
|
def test_no_parameters(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
|
|
||||||
Docstring
|
Docstring
|
||||||
|
|
||||||
""")
|
""")
|
||||||
self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
|
self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
|
||||||
self.assertEqual(1, len(function.parameters)) # self!
|
self.assertEqual(1, len(function.parameters)) # self!
|
||||||
|
|
||||||
def test_init_with_no_parameters(self):
|
def test_init_with_no_parameters(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
module foo
|
module foo
|
||||||
class foo.Bar "unused" "notneeded"
|
class foo.Bar "unused" "notneeded"
|
||||||
foo.Bar.__init__
|
foo.Bar.__init__
|
||||||
|
|
||||||
Docstring
|
Docstring
|
||||||
|
|
||||||
|
""", signatures_in_block=3, function_index=2)
|
||||||
|
|
||||||
""", signatures_in_block=3, function_index=2)
|
|
||||||
# self is not in the signature
|
# self is not in the signature
|
||||||
self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
|
self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
|
||||||
# but it *is* a parameter
|
# but it *is* a parameter
|
||||||
|
@ -652,93 +733,97 @@ Docstring
|
||||||
|
|
||||||
def test_illegal_module_line(self):
|
def test_illegal_module_line(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar => int
|
foo.bar => int
|
||||||
/
|
/
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_illegal_c_basename(self):
|
def test_illegal_c_basename(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar as 935
|
foo.bar as 935
|
||||||
/
|
/
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_single_star(self):
|
def test_single_star(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
|
def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
*
|
*
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
|
def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
*
|
*
|
||||||
Docstring here.
|
Docstring here.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
|
def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
this: int
|
this: int
|
||||||
*
|
*
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
|
def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
this: int
|
this: int
|
||||||
*
|
*
|
||||||
Docstring.
|
Docstring.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_single_slash(self):
|
def test_single_slash(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
/
|
/
|
||||||
/
|
/
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_mix_star_and_slash(self):
|
def test_mix_star_and_slash(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
x: int
|
x: int
|
||||||
y: int
|
y: int
|
||||||
*
|
*
|
||||||
z: int
|
z: int
|
||||||
/
|
/
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_parameters_not_permitted_after_slash_for_now(self):
|
def test_parameters_not_permitted_after_slash_for_now(self):
|
||||||
self.parse_function_should_fail("""
|
self.parse_function_should_fail("""
|
||||||
module foo
|
module foo
|
||||||
foo.bar
|
foo.bar
|
||||||
/
|
/
|
||||||
x: int
|
x: int
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_parameters_no_more_than_one_vararg(self):
|
def test_parameters_no_more_than_one_vararg(self):
|
||||||
s = self.parse_function_should_fail("""
|
expected_msg = (
|
||||||
module foo
|
"Error on line 0:\n"
|
||||||
foo.bar
|
"Too many var args\n"
|
||||||
|
)
|
||||||
|
out = self.parse_function_should_fail("""
|
||||||
|
module foo
|
||||||
|
foo.bar
|
||||||
*vararg1: object
|
*vararg1: object
|
||||||
*vararg2: object
|
*vararg2: object
|
||||||
""")
|
""")
|
||||||
self.assertEqual(s, "Error on line 0:\nToo many var args\n")
|
self.assertEqual(out, expected_msg)
|
||||||
|
|
||||||
def test_function_not_at_column_0(self):
|
def test_function_not_at_column_0(self):
|
||||||
function = self.parse_function("""
|
function = self.parse_function("""
|
||||||
|
@ -749,16 +834,16 @@ foo.bar
|
||||||
*
|
*
|
||||||
y: str
|
y: str
|
||||||
Not at column 0!
|
Not at column 0!
|
||||||
""")
|
""")
|
||||||
self.assertEqual("""
|
self.checkDocstring(function, """
|
||||||
bar($module, /, x, *, y)
|
bar($module, /, x, *, y)
|
||||||
--
|
--
|
||||||
|
|
||||||
Not at column 0!
|
Not at column 0!
|
||||||
|
|
||||||
x
|
x
|
||||||
Nested docstring here, goeth.
|
Nested docstring here, goeth.
|
||||||
""".strip(), function.docstring)
|
""")
|
||||||
|
|
||||||
def test_directive(self):
|
def test_directive(self):
|
||||||
c = FakeClinic()
|
c = FakeClinic()
|
||||||
|
@ -772,46 +857,39 @@ Not at column 0!
|
||||||
def test_legacy_converters(self):
|
def test_legacy_converters(self):
|
||||||
block = self.parse('module os\nos.access\n path: "s"')
|
block = self.parse('module os\nos.access\n path: "s"')
|
||||||
module, function = block.signatures
|
module, function = block.signatures
|
||||||
self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
|
conv = (function.parameters['path']).converter
|
||||||
|
self.assertIsInstance(conv, clinic.str_converter)
|
||||||
|
|
||||||
def test_legacy_converters_non_string_constant_annotation(self):
|
def test_legacy_converters_non_string_constant_annotation(self):
|
||||||
expected_failure_message = """\
|
expected_failure_message = (
|
||||||
Error on line 0:
|
"Error on line 0:\n"
|
||||||
Annotations must be either a name, a function call, or a string.
|
"Annotations must be either a name, a function call, or a string.\n"
|
||||||
"""
|
)
|
||||||
|
dataset = (
|
||||||
s = self.parse_function_should_fail('module os\nos.access\n path: 42')
|
'module os\nos.access\n path: 42',
|
||||||
self.assertEqual(s, expected_failure_message)
|
'module os\nos.access\n path: 42.42',
|
||||||
|
'module os\nos.access\n path: 42j',
|
||||||
s = self.parse_function_should_fail('module os\nos.access\n path: 42.42')
|
'module os\nos.access\n path: b"42"',
|
||||||
self.assertEqual(s, expected_failure_message)
|
)
|
||||||
|
for block in dataset:
|
||||||
s = self.parse_function_should_fail('module os\nos.access\n path: 42j')
|
with self.subTest(block=block):
|
||||||
self.assertEqual(s, expected_failure_message)
|
out = self.parse_function_should_fail(block)
|
||||||
|
self.assertEqual(out, expected_failure_message)
|
||||||
s = self.parse_function_should_fail('module os\nos.access\n path: b"42"')
|
|
||||||
self.assertEqual(s, expected_failure_message)
|
|
||||||
|
|
||||||
def test_other_bizarre_things_in_annotations_fail(self):
|
def test_other_bizarre_things_in_annotations_fail(self):
|
||||||
expected_failure_message = """\
|
expected_failure_message = (
|
||||||
Error on line 0:
|
"Error on line 0:\n"
|
||||||
Annotations must be either a name, a function call, or a string.
|
"Annotations must be either a name, a function call, or a string.\n"
|
||||||
"""
|
|
||||||
|
|
||||||
s = self.parse_function_should_fail(
|
|
||||||
'module os\nos.access\n path: {"some": "dictionary"}'
|
|
||||||
)
|
)
|
||||||
self.assertEqual(s, expected_failure_message)
|
dataset = (
|
||||||
|
'module os\nos.access\n path: {"some": "dictionary"}',
|
||||||
s = self.parse_function_should_fail(
|
'module os\nos.access\n path: ["list", "of", "strings"]',
|
||||||
'module os\nos.access\n path: ["list", "of", "strings"]'
|
'module os\nos.access\n path: (x for x in range(42))',
|
||||||
)
|
)
|
||||||
self.assertEqual(s, expected_failure_message)
|
for block in dataset:
|
||||||
|
with self.subTest(block=block):
|
||||||
s = self.parse_function_should_fail(
|
out = self.parse_function_should_fail(block)
|
||||||
'module os\nos.access\n path: (x for x in range(42))'
|
self.assertEqual(out, expected_failure_message)
|
||||||
)
|
|
||||||
self.assertEqual(s, expected_failure_message)
|
|
||||||
|
|
||||||
def test_kwarg_splats_disallowed_in_function_call_annotations(self):
|
def test_kwarg_splats_disallowed_in_function_call_annotations(self):
|
||||||
expected_error_msg = (
|
expected_error_msg = (
|
||||||
|
@ -945,10 +1023,16 @@ Annotations must be either a name, a function call, or a string.
|
||||||
self.assertEqual(repr(clinic.NULL), '<Null>')
|
self.assertEqual(repr(clinic.NULL), '<Null>')
|
||||||
|
|
||||||
# test that fail fails
|
# test that fail fails
|
||||||
|
expected = (
|
||||||
|
'Error in file "clown.txt" on line 69:\n'
|
||||||
|
'The igloos are melting!\n'
|
||||||
|
)
|
||||||
with support.captured_stdout() as stdout:
|
with support.captured_stdout() as stdout:
|
||||||
with self.assertRaises(SystemExit):
|
with self.assertRaises(SystemExit):
|
||||||
clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69)
|
clinic.fail('The igloos are melting!',
|
||||||
self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n')
|
filename='clown.txt', line_number=69)
|
||||||
|
actual = stdout.getvalue()
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
class ClinicExternalTest(TestCase):
|
class ClinicExternalTest(TestCase):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue