1# Copyright 2016 Google Inc. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Python 3 tests for yapf.reformatter."""
15
16import sys
17import textwrap
18import unittest
19
20from yapf.yapflib import py3compat
21from yapf.yapflib import reformatter
22from yapf.yapflib import style
23
24from yapftests import yapf_test_helper
25
26
27@unittest.skipUnless(py3compat.PY3, 'Requires Python 3')
28class TestsForPython3Code(yapf_test_helper.YAPFTest):
29  """Test a few constructs that are new Python 3 syntax."""
30
31  @classmethod
32  def setUpClass(cls):
33    style.SetGlobalStyle(style.CreatePEP8Style())
34
35  def testTypedNames(self):
36    unformatted_code = textwrap.dedent("""\
37        def x(aaaaaaaaaaaaaaa:int,bbbbbbbbbbbbbbbb:str,ccccccccccccccc:dict,eeeeeeeeeeeeee:set={1, 2, 3})->bool:
38          pass
39        """)
40    expected_formatted_code = textwrap.dedent("""\
41        def x(aaaaaaaaaaaaaaa: int,
42              bbbbbbbbbbbbbbbb: str,
43              ccccccccccccccc: dict,
44              eeeeeeeeeeeeee: set = {1, 2, 3}) -> bool:
45            pass
46        """)
47    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
48    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
49
50  def testKeywordOnlyArgSpecifier(self):
51    unformatted_code = textwrap.dedent("""\
52        def foo(a, *, kw):
53          return a+kw
54        """)
55    expected_formatted_code = textwrap.dedent("""\
56        def foo(a, *, kw):
57            return a + kw
58        """)
59    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
60    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
61
62  @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6')
63  def testPEP448ParameterExpansion(self):
64    unformatted_code = textwrap.dedent("""\
65    { ** x }
66    {   **{}   }
67    { **{   **x },  **x }
68    {'a': 1,   **kw , 'b':3,  **kw2   }
69    """)
70    expected_formatted_code = textwrap.dedent("""\
71    {**x}
72    {**{}}
73    {**{**x}, **x}
74    {'a': 1, **kw, 'b': 3, **kw2}
75    """)
76    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
77    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
78
79  def testAnnotations(self):
80    unformatted_code = textwrap.dedent("""\
81        def foo(a: list, b: "bar") -> dict:
82          return a+b
83        """)
84    expected_formatted_code = textwrap.dedent("""\
85        def foo(a: list, b: "bar") -> dict:
86            return a + b
87        """)
88    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
89    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
90
91  def testExecAsNonKeyword(self):
92    unformatted_code = 'methods.exec( sys.modules[name])\n'
93    expected_formatted_code = 'methods.exec(sys.modules[name])\n'
94    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
95    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
96
97  def testAsyncFunctions(self):
98    if sys.version_info[1] < 5:
99      return
100    code = textwrap.dedent("""\
101        import asyncio
102        import time
103
104
105        @print_args
106        async def slow_operation():
107            await asyncio.sleep(1)
108            # print("Slow operation {} complete".format(n))
109
110
111        async def main():
112            start = time.time()
113            if (await get_html()):
114                pass
115        """)
116    uwlines = yapf_test_helper.ParseAndUnwrap(code)
117    self.assertCodeEqual(code, reformatter.Reformat(uwlines, verify=False))
118
119  def testNoSpacesAroundPowerOperator(self):
120    try:
121      style.SetGlobalStyle(
122          style.CreateStyleFromConfig(
123              '{based_on_style: pep8, SPACES_AROUND_POWER_OPERATOR: True}'))
124      unformatted_code = textwrap.dedent("""\
125          a**b
126          """)
127      expected_formatted_code = textwrap.dedent("""\
128          a ** b
129          """)
130      uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
131      self.assertCodeEqual(expected_formatted_code,
132                           reformatter.Reformat(uwlines))
133    finally:
134      style.SetGlobalStyle(style.CreatePEP8Style())
135
136  def testSpacesAroundDefaultOrNamedAssign(self):
137    try:
138      style.SetGlobalStyle(
139          style.CreateStyleFromConfig(
140              '{based_on_style: pep8, '
141              'SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN: True}'))
142      unformatted_code = textwrap.dedent("""\
143          f(a=5)
144          """)
145      expected_formatted_code = textwrap.dedent("""\
146          f(a = 5)
147          """)
148      uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
149      self.assertCodeEqual(expected_formatted_code,
150                           reformatter.Reformat(uwlines))
151    finally:
152      style.SetGlobalStyle(style.CreatePEP8Style())
153
154  def testTypeHint(self):
155    unformatted_code = textwrap.dedent("""\
156        def foo(x: int=42):
157            pass
158
159
160        def foo2(x: 'int' =42):
161            pass
162        """)
163    expected_formatted_code = textwrap.dedent("""\
164        def foo(x: int = 42):
165            pass
166
167
168        def foo2(x: 'int' = 42):
169            pass
170        """)
171    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
172    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
173
174  def testMatrixMultiplication(self):
175    unformatted_code = textwrap.dedent("""\
176        a=b@c
177        """)
178    expected_formatted_code = textwrap.dedent("""\
179        a = b @ c
180        """)
181    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
182    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
183
184  def testNoneKeyword(self):
185    code = """\
186None.__ne__()
187"""
188    uwlines = yapf_test_helper.ParseAndUnwrap(code)
189    self.assertCodeEqual(code, reformatter.Reformat(uwlines))
190
191  def testAsyncWithPrecedingComment(self):
192    if sys.version_info[1] < 5:
193      return
194    unformatted_code = textwrap.dedent("""\
195        import asyncio
196
197        # Comment
198        async def bar():
199            pass
200
201        async def foo():
202            pass
203        """)
204    expected_formatted_code = textwrap.dedent("""\
205        import asyncio
206
207
208        # Comment
209        async def bar():
210            pass
211
212
213        async def foo():
214            pass
215        """)
216    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
217    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
218
219  def testAsyncFunctionsNested(self):
220    if sys.version_info[1] < 5:
221      return
222    code = textwrap.dedent("""\
223        async def outer():
224            async def inner():
225                pass
226        """)
227    uwlines = yapf_test_helper.ParseAndUnwrap(code)
228    self.assertCodeEqual(code, reformatter.Reformat(uwlines))
229
230  def testKeepTypesIntact(self):
231    if sys.version_info[1] < 5:
232      return
233    unformatted_code = textwrap.dedent("""\
234        def _ReduceAbstractContainers(
235            self, *args: Optional[automation_converter.PyiCollectionAbc]) -> List[
236                automation_converter.PyiCollectionAbc]:
237            pass
238        """)
239    expected_formatted_code = textwrap.dedent("""\
240        def _ReduceAbstractContainers(
241                self, *args: Optional[automation_converter.PyiCollectionAbc]
242        ) -> List[automation_converter.PyiCollectionAbc]:
243            pass
244        """)
245    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
246    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
247
248  def testContinuationIndentWithAsync(self):
249    if sys.version_info[1] < 5:
250      return
251    unformatted_code = textwrap.dedent("""\
252        async def start_websocket():
253            async with session.ws_connect(
254                r"ws://a_really_long_long_long_long_long_long_url") as ws:
255                pass
256        """)
257    expected_formatted_code = textwrap.dedent("""\
258        async def start_websocket():
259            async with session.ws_connect(
260                    r"ws://a_really_long_long_long_long_long_long_url") as ws:
261                pass
262        """)
263    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
264    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
265
266  def testSplittingArguments(self):
267    if sys.version_info[1] < 5:
268      return
269    try:
270      style.SetGlobalStyle(
271          style.CreateStyleFromConfig(
272              '{based_on_style: pep8, '
273              'dedent_closing_brackets: true, '
274              'coalesce_brackets: false, '
275              'space_between_ending_comma_and_closing_bracket: false, '
276              'split_arguments_when_comma_terminated: true, '
277              'split_before_first_argument: true}'))
278      unformatted_code = """\
279async def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
280    pass
281
282async def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None):
283    pass
284
285def open_file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
286    pass
287
288def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None):
289    pass
290"""
291      expected_formatted_code = """\
292async def open_file(
293        file,
294        mode='r',
295        buffering=-1,
296        encoding=None,
297        errors=None,
298        newline=None,
299        closefd=True,
300        opener=None
301):
302    pass
303
304
305async def run_sync_in_worker_thread(
306        sync_fn, *args, cancellable=False, limiter=None
307):
308    pass
309
310
311def open_file(
312        file,
313        mode='r',
314        buffering=-1,
315        encoding=None,
316        errors=None,
317        newline=None,
318        closefd=True,
319        opener=None
320):
321    pass
322
323
324def run_sync_in_worker_thread(sync_fn, *args, cancellable=False, limiter=None):
325    pass
326"""
327      uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
328      self.assertCodeEqual(expected_formatted_code,
329                           reformatter.Reformat(uwlines))
330    finally:
331      style.SetGlobalStyle(style.CreatePEP8Style())
332
333  def testDictUnpacking(self):
334    if sys.version_info[1] < 5:
335      return
336    unformatted_code = """\
337class Foo:
338    def foo(self):
339        foofoofoofoofoofoofoofoo('foofoofoofoofoo', {
340
341            'foo': 'foo',
342
343            **foofoofoo
344        })
345"""
346    expected_formatted_code = """\
347class Foo:
348    def foo(self):
349        foofoofoofoofoofoofoofoo('foofoofoofoofoo', {
350            'foo': 'foo',
351            **foofoofoo
352        })
353"""
354    uwlines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
355    self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(uwlines))
356
357  def testMultilineFormatString(self):
358    if sys.version_info[1] < 6:
359      return
360    code = """\
361# yapf: disable
362(f'''
363  ''')
364# yapf: enable
365"""
366    # https://github.com/google/yapf/issues/513
367    uwlines = yapf_test_helper.ParseAndUnwrap(code)
368    self.assertCodeEqual(code, reformatter.Reformat(uwlines))
369
370  def testEllipses(self):
371    if sys.version_info[1] < 6:
372      return
373    code = """\
374def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None:
375    return
376"""
377    # https://github.com/google/yapf/issues/533
378    uwlines = yapf_test_helper.ParseAndUnwrap(code)
379    self.assertCodeEqual(code, reformatter.Reformat(uwlines))
380
381
382if __name__ == '__main__':
383  unittest.main()
384