diff --git a/.travis.yml b/.travis.yml index 1d669dc7..932093b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ install: pip install -U "pexpect>=3.3" pyflakes pytest epydoc rlipython requests jupyter flaky flake8; else pip install -U git+https://github.com/asmeurer/jupyter_console@display_completions; - pip install -U "pexpect>=3.3" pyflakes pytest rlipython requests jupyter flaky flake8 'notebook<6.1'; + pip install -U "pexpect>=3.3" pyflakes pytest rlipython requests jupyter flaky flake8 'notebook<6.1' 'prompt_toolkit<3.0.6'; fi - if [[ "${DOCS}" == "true" ]]; then pip install sphinx sphinx_rtd_theme sphinx-autodoc-typehints; diff --git a/lib/python/pyflyby/_parse.py b/lib/python/pyflyby/_parse.py index 5416a2ec..6e768fea 100644 --- a/lib/python/pyflyby/_parse.py +++ b/lib/python/pyflyby/_parse.py @@ -115,6 +115,12 @@ def _iter_child_nodes_in_order_internal_1(node): elif isinstance(node, ast.IfExp): assert node._fields == ('test', 'body', 'orelse') yield node.body, node.test, node.orelse + elif isinstance(node, ast.Call): + # call arguments order are lost by ast, re-order them + yield node.func + args = sorted([(k.value.lineno, k.value.col_offset, k) for k in node.keywords]+ + [(k.lineno,k.col_offset, k) for k in node.args]) + yield [a[2] for a in args] elif isinstance(node, ast.ClassDef): if six.PY2: assert node._fields == ('name', 'bases', 'body', 'decorator_list') diff --git a/pytest.ini b/pytest.ini index b3147073..4f672b6b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,5 +1,6 @@ [pytest] # IGNORE_EXCEPTION_DETAIL prevents doctest from testing the exception message, but is necessary for Python 2/3 compatibility doctest_optionflags= ALLOW_UNICODE ALLOW_BYTES IGNORE_EXCEPTION_DETAIL +addopts = --durations=10 filterwarnings = error::DeprecationWarning diff --git a/tests/test_parse.py b/tests/test_parse.py index 5988ec8a..5d5b4199 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -1295,3 +1295,14 @@ def test_parsable_missing_flags_no_auto_flags_1(): def test_parsable_missing_flags_auto_flags_1(): block = PythonBlock("print(3, file=4)", auto_flags=True) assert block.parsable + +@pytest.mark.skipif(sys.version_info < (3,7), reason='invalid early python syntax') +@pytest.mark.parametrize('input', [ + "print(abc=123, *args, **kwargs)", + "print(*args, ijk=123, **kwargs)", + "print(7, *args, **kwargs)", + "print(*args, 12, **kwargs)", + ]) +def test_parsable_Call_Ast_args_kwargs(input): + block = PythonBlock(input, auto_flags=True) + assert block.annotated_ast_node