summaryrefslogtreecommitdiff
path: root/pycodestyle.py
diff options
context:
space:
mode:
Diffstat (limited to 'pycodestyle.py')
-rwxr-xr-xpycodestyle.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/pycodestyle.py b/pycodestyle.py
index 5b7a39c..d31ac9e 100755
--- a/pycodestyle.py
+++ b/pycodestyle.py
@@ -1388,6 +1388,57 @@ def python_3000_backticks(logical_line):
yield pos, "W604 backticks are deprecated, use 'repr()'"
+@register_check
+def python_3000_invalid_escape_sequence(logical_line, tokens):
+ r"""Invalid escape sequences are deprecated in Python 3.6.
+
+ Okay: regex = r'\.png$'
+ W605: regex = '\.png$'
+ """
+ # https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
+ valid = [
+ '\n',
+ '\\',
+ '\'',
+ '"',
+ 'a',
+ 'b',
+ 'f',
+ 'n',
+ 'r',
+ 't',
+ 'v',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ 'x',
+
+ # Escape sequences only recognized in string literals
+ 'N',
+ 'u',
+ 'U',
+ ]
+
+ for token_type, text, start, end, line in tokens:
+ if token_type == tokenize.STRING:
+ quote = text[-3:] if text[-3:] in ('"""', "'''") else text[-1]
+ # Extract string modifiers (e.g. u or r)
+ quote_pos = text.index(quote)
+ prefix = text[:quote_pos].lower()
+ start = quote_pos + len(quote)
+ string = text[start:-len(quote)]
+
+ if 'r' not in prefix:
+ pos = string.find('\\')
+ while pos >= 0:
+ pos += 1
+ if string[pos] not in valid:
+ yield (
+ pos,
+ "W605 invalid escape sequence '\\%s'" %
+ string[pos],
+ )
+ pos = string.find('\\', pos + 1)
+
+
##############################################################################
# Helper functions
##############################################################################