diff options
author | Ian Stapleton Cordasco <graffatcolmingov@gmail.com> | 2018-02-17 15:01:03 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-17 15:01:03 -0600 |
commit | eb91b79ab38aad4d44a3b52b02605412f32ba5ae (patch) | |
tree | 1b37b5704da2c84b8dc53c5b9fbc160435c019a2 | |
parent | 01ecae5a87d2bdf7df6528722e0c2ae36930d90f (diff) | |
parent | 1711fb429ae4815faa55bc9ccceca59f27f88706 (diff) | |
download | pep8-eb91b79ab38aad4d44a3b52b02605412f32ba5ae.tar.gz |
Merge pull request #684 from jdufresne/async-await
Add W606 warning for async and await keywords in Python 3.7
-rw-r--r-- | CHANGES.txt | 2 | ||||
-rw-r--r-- | docs/intro.rst | 2 | ||||
-rwxr-xr-x | pycodestyle.py | 54 | ||||
-rw-r--r-- | testsuite/W60.py | 45 |
4 files changed, 103 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index af06645..25b8558 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,6 +9,8 @@ New checks: * Add W504 warning for checking that a break doesn't happen after a binary operator. This check is ignored by default * Add W605 warning for invalid escape sequences in string literals +* Add W606 warning for 'async' and 'await' reserved keywords being introduced + in Python 3.7 2.3.1 (2017-01-31) ------------------ diff --git a/docs/intro.rst b/docs/intro.rst index 854dc54..80ef08f 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -419,6 +419,8 @@ This is the current list of error and warning codes: +------------+----------------------------------------------------------------------+ | W605 | invalid escape sequence '\x' | +------------+----------------------------------------------------------------------+ +| W606 | 'async' and 'await' are reserved keywords starting with Python 3.7 | ++------------+----------------------------------------------------------------------+ **(*)** In the default configuration, the checks **E121**, **E123**, **E126**, diff --git a/pycodestyle.py b/pycodestyle.py index 7131f2a..5f02187 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -1507,6 +1507,60 @@ def python_3000_invalid_escape_sequence(logical_line, tokens): pos = string.find('\\', pos + 1) +@register_check +def python_3000_async_await_keywords(logical_line, tokens): + """'async' and 'await' are reserved keywords starting with Python 3.7 + + W606: async = 42 + W606: await = 42 + Okay: async def read_data(db):\n data = await db.fetch('SELECT ...') + """ + # The Python tokenize library before Python 3.5 recognizes async/await as a + # NAME token. Therefore, use a state machine to look for the possible + # async/await constructs as defined by the Python grammar: + # https://docs.python.org/3/reference/grammar.html + + state = None + for token_type, text, start, end, line in tokens: + error = False + + if state is None: + if token_type == tokenize.NAME: + if text == 'async': + state = ('async_stmt', start) + elif text == 'await': + state = ('await', start) + elif state[0] == 'async_stmt': + if token_type == tokenize.NAME and text in ('def', 'with', 'for'): + # One of funcdef, with_stmt, or for_stmt. Return to looking + # for async/await names. + state = None + else: + error = True + elif state[0] == 'await': + if token_type in (tokenize.NAME, tokenize.NUMBER, tokenize.STRING): + # An await expression. Return to looking for async/await names. + state = None + else: + error = True + + if error: + yield ( + state[1], + "W606 'async' and 'await' are reserved keywords starting with " + "Python 3.7", + ) + state = None + + # Last token + if state is not None: + yield ( + state[1], + "W606 'async' and 'await' are reserved keywords starting with " + "Python 3.7", + ) + + ############################################################################## # Helper functions ############################################################################## diff --git a/testsuite/W60.py b/testsuite/W60.py index cbe267d..030bec5 100644 --- a/testsuite/W60.py +++ b/testsuite/W60.py @@ -29,3 +29,48 @@ regex = r''' \\.png$ ''' s = '\\' +#: W606 +async = 42 +#: W606 +await = 42 +#: W606 +def async(): + pass +#: W606 +def await(): + pass +#: W606 +class async: + pass +#: W606 +class await: + pass +#: Okay +async def read_data(db): + data = await db.fetch('SELECT ...') +#: Okay +if await fut: + pass +if (await fut): + pass +if await fut + 1: + pass +if (await fut) + 1: + pass +pair = await fut, 'spam' +pair = (await fut), 'spam' +with await fut, open(): + pass +with (await fut), open(): + pass +await foo()['spam'].baz()() +return await coro() +return (await coro()) +res = await coro() ** 2 +res = (await coro()) ** 2 +func(a1=await coro(), a2=0) +func(a1=(await coro()), a2=0) +await foo() + await bar() +(await foo()) + (await bar()) +-await foo() +-(await foo()) |