summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pre-commit-config.yaml17
-rw-r--r--docs/conf.py87
-rwxr-xr-xpycodestyle.py29
-rw-r--r--setup.py1
-rw-r--r--testsuite/E20.py23
-rw-r--r--testsuite/E27.py2
-rw-r--r--testsuite/python3.py2
-rw-r--r--testsuite/python310.py23
-rw-r--r--testsuite/python38.py14
9 files changed, 122 insertions, 76 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..6cbf31c
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,17 @@
+exclude: ^testsuite/
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.0.1
+ hooks:
+ - id: check-yaml
+ - id: debug-statements
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+- repo: https://github.com/asottile/reorder_python_imports
+ rev: v2.6.0
+ hooks:
+ - id: reorder-python-imports
+- repo: https://github.com/pycqa/flake8
+ rev: 3.9.2
+ hooks:
+ - id: flake8
diff --git a/docs/conf.py b/docs/conf.py
index 7935b0b..a89a2e0 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -11,20 +11,19 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
-
-import sys
import os
+import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+# sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('..'))
# -- General configuration ----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
@@ -38,7 +37,7 @@ templates_path = ['_templates']
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@@ -61,13 +60,13 @@ release = '.'.join(pkg_version)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -75,24 +74,24 @@ exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for
# all documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# -- Options for HTML output --------------------------------------------------
@@ -108,26 +107,26 @@ if not on_rtd: # only import and set the theme if we're building docs locally
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -136,44 +135,44 @@ if not on_rtd: # only import and set the theme if we're building docs locally
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'pycodestyledoc'
@@ -183,13 +182,13 @@ htmlhelp_basename = 'pycodestyledoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
- #'papersize': 'letterpaper',
+ # 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
- #'pointsize': '10pt',
+ # 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
- #'preamble': '',
+ # 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
@@ -202,23 +201,23 @@ latex_documents = [
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output -------------------------------------------
@@ -231,7 +230,7 @@ man_pages = [
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output -----------------------------------------------
@@ -246,10 +245,10 @@ texinfo_documents = [
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
diff --git a/pycodestyle.py b/pycodestyle.py
index 68d31d4..aa70791 100755
--- a/pycodestyle.py
+++ b/pycodestyle.py
@@ -25,7 +25,6 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-
r"""
Check Python source code formatting, according to PEP 8.
@@ -49,6 +48,7 @@ W warnings
"""
from __future__ import with_statement
+import bisect
import inspect
import keyword
import os
@@ -57,7 +57,6 @@ import sys
import time
import tokenize
import warnings
-import bisect
try:
from functools import lru_cache
@@ -144,7 +143,7 @@ RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$')
ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
DOCSTRING_REGEX = re.compile(r'u?r?["\']')
-EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({] | [\]}),;]| :(?!=)')
+EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({][ \t]|[ \t][\]}),;:](?!=)')
WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
r'\s*(?(1)|(None|False|True))\b')
@@ -169,8 +168,7 @@ STARTSWITH_INDENT_STATEMENT_REGEX = re.compile(
'while',
)))
)
-DUNDER_REGEX = re.compile(r'^__([^\s]+)__ = ')
-MATCH_CASE_REGEX = re.compile(r'^\s*\b(?:match|case)(\s*)(?=.*\:)')
+DUNDER_REGEX = re.compile(r"^__([^\s]+)__(?::\s*[a-zA-Z.0-9_\[\]\"]+)? = ")
BLANK_EXCEPT_REGEX = re.compile(r"except\s*:")
_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
@@ -471,7 +469,7 @@ def extraneous_whitespace(logical_line):
text = match.group()
char = text.strip()
found = match.start()
- if text == char + ' ':
+ if text[-1].isspace():
# assert char in '([{'
yield found + 1, "E201 whitespace after '%s'" % char
elif line[found - 1] != ',':
@@ -502,16 +500,6 @@ def whitespace_around_keywords(logical_line):
elif len(after) > 1:
yield match.start(2), "E271 multiple spaces after keyword"
- if sys.version_info >= (3, 10):
- match = MATCH_CASE_REGEX.match(logical_line)
- if match:
- if match[1] == ' ':
- return
- if match[1] == '':
- yield match.start(1), "E275 missing whitespace after keyword"
- else:
- yield match.start(1), "E271 multiple spaces after keyword"
-
@register_check
def missing_whitespace_after_import_keyword(logical_line):
@@ -965,8 +953,13 @@ def missing_whitespace_around_operator(logical_line, tokens):
# Check if the operator is used as a binary operator
# Allow unary operators: -123, -x, +1.
# Allow argument unpacking: foo(*args, **kwargs).
- if (prev_text in '}])' if prev_type == tokenize.OP
- else prev_text not in KEYWORDS):
+ if prev_type == tokenize.OP and prev_text in '}])' or (
+ prev_type != tokenize.OP and
+ prev_text not in KEYWORDS and (
+ sys.version_info < (3, 9) or
+ not keyword.issoftkeyword(prev_text)
+ )
+ ):
need_space = None
elif text in WS_OPTIONAL_OPERATORS:
need_space = None
diff --git a/setup.py b/setup.py
index 148751b..3f0c363 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-from __future__ import with_statement
from setuptools import setup
diff --git a/testsuite/E20.py b/testsuite/E20.py
index 2f1ecc2..20c6dfd 100644
--- a/testsuite/E20.py
+++ b/testsuite/E20.py
@@ -4,6 +4,12 @@ spam( ham[1], {eggs: 2})
spam(ham[ 1], {eggs: 2})
#: E201:1:15
spam(ham[1], { eggs: 2})
+#: E201:1:6
+spam( ham[1], {eggs: 2})
+#: E201:1:10
+spam(ham[ 1], {eggs: 2})
+#: E201:1:15
+spam(ham[1], { eggs: 2})
#: Okay
spam(ham[1], {eggs: 2})
#:
@@ -15,6 +21,12 @@ spam(ham[1], {eggs: 2} )
spam(ham[1], {eggs: 2 })
#: E202:1:11
spam(ham[1 ], {eggs: 2})
+#: E202:1:23
+spam(ham[1], {eggs: 2} )
+#: E202:1:22
+spam(ham[1], {eggs: 2 })
+#: E202:1:11
+spam(ham[1 ], {eggs: 2})
#: Okay
spam(ham[1], {eggs: 2})
@@ -39,13 +51,24 @@ result = [
if x == 4 :
print x, y
x, y = y, x
+#: E203:1:10
+if x == 4 :
+ print x, y
+ x, y = y, x
#: E203:2:15 E702:2:16
if x == 4:
print x, y ; x, y = y, x
+#: E203:2:15 E702:2:16
+if x == 4:
+ print x, y ; x, y = y, x
#: E203:3:13
if x == 4:
print x, y
x, y = y , x
+#: E203:3:13
+if x == 4:
+ print x, y
+ x, y = y , x
#: Okay
if x == 4:
print x, y
diff --git a/testsuite/E27.py b/testsuite/E27.py
index 888b3a8..9bb53f8 100644
--- a/testsuite/E27.py
+++ b/testsuite/E27.py
@@ -42,3 +42,5 @@ try:
from importable.module import(e, f)
except ImportError:
pass
+#: Okay
+matched = {"true": True, "false": False}
diff --git a/testsuite/python3.py b/testsuite/python3.py
index 709695a..959956e 100644
--- a/testsuite/python3.py
+++ b/testsuite/python3.py
@@ -9,6 +9,8 @@ def foo(x: int) -> int:
# Annotated variables #575
CONST: int = 42
+match: int = 42
+case: int = 42
class Class:
diff --git a/testsuite/python310.py b/testsuite/python310.py
index e78d372..2355f55 100644
--- a/testsuite/python310.py
+++ b/testsuite/python310.py
@@ -7,21 +7,18 @@ match (var, var2):
pass
case _:
print("Default")
-#: E271:2:6 E271:3:9 E271:5:9 E271:7:9
-var = 1
-match var:
- case 1:
+#: Okay
+var = 0, 1, 2
+match var:
+ case *_, 1, 2:
+ pass
+ case 0, *_, 2:
pass
- case 2:
+ case 0, 1, *_:
pass
- case (
- 3
- ):
+ case (*_, 1, 2):
pass
-#: E275:2:6 E275:3:9 E275:5:9
-var = 1
-match(var):
- case(1):
+ case (0, *_, 2):
pass
- case_:
+ case (0, 1, *_):
pass
diff --git a/testsuite/python38.py b/testsuite/python38.py
index f927673..1374192 100644
--- a/testsuite/python38.py
+++ b/testsuite/python38.py
@@ -28,3 +28,17 @@ if x:= 1:
#: E225:1:18
if False or (x :=1):
pass
+#: Okay
+import typing as t
+
+__all__: t.List[str] = []
+
+import logging
+
+logging.getLogger(__name__)
+#: E402
+import typing as t
+
+all_the_things: t.List[str] = []
+
+import logging