Skip to content

Commit 598092f

Browse files
authored
Merge pull request #1038 from asottile/drop-python-2
drop support for python 2.x
2 parents abc475c + a9b6098 commit 598092f

File tree

6 files changed

+60
-92
lines changed

6 files changed

+60
-92
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,12 @@ jobs:
1010
strategy:
1111
matrix:
1212
include:
13-
- os: windows-latest
14-
py: 2.7
15-
toxenv: py
1613
- os: windows-latest
1714
py: 3.9
1815
toxenv: py
19-
- os: ubuntu-latest
20-
py: pypy2
21-
toxenv: py
2216
- os: ubuntu-latest
2317
py: pypy3
2418
toxenv: py
25-
- os: ubuntu-latest
26-
py: 2.7
27-
toxenv: py
28-
- os: ubuntu-latest
29-
py: 3.5
30-
toxenv: py
3119
- os: ubuntu-latest
3220
py: 3.6
3321
toxenv: py

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ repos:
1111
rev: v2.6.0
1212
hooks:
1313
- id: reorder-python-imports
14+
args: [--py36-plus]
15+
- repo: https://github.com/asottile/pyupgrade
16+
rev: v2.29.0
17+
hooks:
18+
- id: pyupgrade
19+
args: [--py36-plus]
1420
- repo: https://github.com/pycqa/flake8
1521
rev: 4.0.1
1622
hooks:

docs/conf.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
#
32
# pycodestyle documentation build configuration file, created by
43
# sphinx-quickstart on Tue Aug 21 09:47:49 2012.
@@ -43,9 +42,9 @@
4342
master_doc = 'index'
4443

4544
# General information about the project.
46-
project = u'pycodestyle'
47-
authors = u'Johann C. Rocholl, Florent Xicluna, Ian Lee'
48-
copyright = u'2006-2016, %s' % (authors)
45+
project = 'pycodestyle'
46+
authors = 'Johann C. Rocholl, Florent Xicluna, Ian Lee'
47+
copyright = '2006-2016, %s' % (authors)
4948

5049
# The version info for the project you're documenting, acts as replacement for
5150
# |version| and |release|, also used in various other places throughout the
@@ -195,7 +194,7 @@
195194
# (source start file, target name, title,
196195
# author, documentclass [howto/manual]).
197196
latex_documents = [
198-
('index', 'pycodestyle.tex', u'pycodestyle documentation',
197+
('index', 'pycodestyle.tex', 'pycodestyle documentation',
199198
authors, 'manual'),
200199
]
201200

@@ -225,7 +224,7 @@
225224
# One entry per manual page. List of tuples
226225
# (source start file, name, description, authors, manual section).
227226
man_pages = [
228-
('index', 'pycodestyle', u'pycodestyle documentation',
227+
('index', 'pycodestyle', 'pycodestyle documentation',
229228
[authors], 1)
230229
]
231230

@@ -239,7 +238,7 @@
239238
# (source start file, target name, title, author,
240239
# dir menu entry, description, category)
241240
texinfo_documents = [
242-
('index', 'pycodestyle', u'pycodestyle documentation', authors,
241+
('index', 'pycodestyle', 'pycodestyle documentation', authors,
243242
'pycodestyle', 'One line description of project.',
244243
'Miscellaneous'),
245244
]

pycodestyle.py

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@
4646
700 statements
4747
900 syntax error
4848
"""
49-
from __future__ import with_statement
50-
5149
import bisect
5250
import inspect
5351
import keyword
@@ -122,14 +120,11 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
122120
UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
123121
ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-', '@'])
124122
WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
125-
# Warn for -> function annotation operator in py3.5+ (issue 803)
126-
FUNCTION_RETURN_ANNOTATION_OP = ['->'] if sys.version_info >= (3, 5) else []
127123
ASSIGNMENT_EXPRESSION_OP = [':='] if sys.version_info >= (3, 8) else []
128124
WS_NEEDED_OPERATORS = frozenset([
129125
'**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
130126
'%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=',
131-
'and', 'in', 'is', 'or'] +
132-
FUNCTION_RETURN_ANNOTATION_OP +
127+
'and', 'in', 'is', 'or', '->'] +
133128
ASSIGNMENT_EXPRESSION_OP)
134129
WHITESPACE = frozenset(' \t')
135130
NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
@@ -158,7 +153,7 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
158153
STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b')
159154
STARTSWITH_TOP_LEVEL_REGEX = re.compile(r'^(async\s+def\s+|def\s+|class\s+|@)')
160155
STARTSWITH_INDENT_STATEMENT_REGEX = re.compile(
161-
r'^\s*({0})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
156+
r'^\s*({})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
162157
'def', 'async def',
163158
'for', 'async for',
164159
'if', 'elif', 'else',
@@ -175,13 +170,10 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
175170

176171

177172
def _get_parameters(function):
178-
if sys.version_info >= (3, 3):
179-
return [parameter.name
180-
for parameter
181-
in inspect.signature(function).parameters.values()
182-
if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
183-
else:
184-
return inspect.getargspec(function)[0]
173+
return [parameter.name
174+
for parameter
175+
in inspect.signature(function).parameters.values()
176+
if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
185177

186178

187179
def register_check(check, codes=None):
@@ -429,8 +421,8 @@ def blank_lines(logical_line, blank_lines, indent_level, line_number,
429421
yield 0, "E306 expected %s blank line before a " \
430422
"nested definition, found 0" % (method_lines,)
431423
else:
432-
yield 0, "E301 expected %s blank line, found 0" % (
433-
method_lines,)
424+
yield 0, "E301 expected {} blank line, found 0".format(
425+
method_lines)
434426
elif blank_before != top_level_lines:
435427
yield 0, "E302 expected %s blank lines, found %d" % (
436428
top_level_lines, blank_before)
@@ -474,7 +466,7 @@ def extraneous_whitespace(logical_line):
474466
yield found + 1, "E201 whitespace after '%s'" % char
475467
elif line[found - 1] != ',':
476468
code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
477-
yield found, "%s whitespace before '%s'" % (code, char)
469+
yield found, f"{code} whitespace before '{char}'"
478470

479471

480472
@register_check
@@ -735,7 +727,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
735727
indent[depth] = start[1]
736728
indent_chances[start[1]] = True
737729
if verbose >= 4:
738-
print("bracket depth %s indent to %s" % (depth, start[1]))
730+
print(f"bracket depth {depth} indent to {start[1]}")
739731
# deal with implicit string concatenation
740732
elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
741733
text in ('u', 'ur', 'b', 'br')):
@@ -1228,7 +1220,7 @@ def compound_statements(logical_line):
12281220
lambda_kw = LAMBDA_REGEX.search(line, 0, found)
12291221
if lambda_kw:
12301222
before = line[:lambda_kw.start()].rstrip()
1231-
if before[-1:] == '=' and isidentifier(before[:-1].strip()):
1223+
if before[-1:] == '=' and before[:-1].strip().isidentifier():
12321224
yield 0, ("E731 do not assign a lambda expression, use a "
12331225
"def")
12341226
break
@@ -1473,7 +1465,7 @@ def comparison_type(logical_line, noqa):
14731465
match = COMPARE_TYPE_REGEX.search(logical_line)
14741466
if match and not noqa:
14751467
inst = match.group(1)
1476-
if inst and isidentifier(inst) and inst not in SINGLETONS:
1468+
if inst and inst.isidentifier() and inst not in SINGLETONS:
14771469
return # Allow comparison for types which are not obvious
14781470
yield match.start(), "E721 do not compare types, use 'isinstance()'"
14791471

@@ -1822,30 +1814,21 @@ def maximum_doc_length(logical_line, max_doc_length, noqa, tokens):
18221814
########################################################################
18231815

18241816

1825-
if sys.version_info < (3,):
1826-
# Python 2: implicit encoding.
1827-
def readlines(filename):
1828-
"""Read the source code."""
1829-
with open(filename, 'rU') as f:
1817+
def readlines(filename):
1818+
"""Read the source code."""
1819+
try:
1820+
with tokenize.open(filename) as f:
1821+
return f.readlines()
1822+
except (LookupError, SyntaxError, UnicodeError):
1823+
# Fall back if file encoding is improperly declared
1824+
with open(filename, encoding='latin-1') as f:
18301825
return f.readlines()
1831-
isidentifier = re.compile(r'[a-zA-Z_]\w*$').match
1832-
stdin_get_value = sys.stdin.read
1833-
else:
1834-
# Python 3
1835-
def readlines(filename):
1836-
"""Read the source code."""
1837-
try:
1838-
with tokenize.open(filename) as f:
1839-
return f.readlines()
1840-
except (LookupError, SyntaxError, UnicodeError):
1841-
# Fall back if file encoding is improperly declared
1842-
with open(filename, encoding='latin-1') as f:
1843-
return f.readlines()
1844-
isidentifier = str.isidentifier
1845-
1846-
def stdin_get_value():
1847-
"""Read the value from stdin."""
1848-
return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1826+
1827+
1828+
def stdin_get_value():
1829+
"""Read the value from stdin."""
1830+
return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1831+
18491832

18501833
noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search)
18511834

@@ -1911,7 +1894,7 @@ def parse_udiff(diff, patterns=None, parent='.'):
19111894
continue
19121895
if line[:3] == '@@ ':
19131896
hunk_match = HUNK_REGEX.match(line)
1914-
(row, nrows) = [int(g or '1') for g in hunk_match.groups()]
1897+
(row, nrows) = (int(g or '1') for g in hunk_match.groups())
19151898
rv[path].update(range(row, row + nrows))
19161899
elif line[:3] == '+++':
19171900
path = line[4:].split('\t', 1)[0]
@@ -1972,7 +1955,7 @@ def _is_eol_token(token):
19721955
########################################################################
19731956

19741957

1975-
class Checker(object):
1958+
class Checker:
19761959
"""Load a Python source file, tokenize it, check coding style."""
19771960

19781961
def __init__(self, filename=None, lines=None,
@@ -2004,9 +1987,9 @@ def __init__(self, filename=None, lines=None,
20041987
elif lines is None:
20051988
try:
20061989
self.lines = readlines(filename)
2007-
except IOError:
1990+
except OSError:
20081991
(exc_type, exc) = sys.exc_info()[:2]
2009-
self._io_error = '%s: %s' % (exc_type.__name__, exc)
1992+
self._io_error = f'{exc_type.__name__}: {exc}'
20101993
self.lines = []
20111994
else:
20121995
self.lines = lines
@@ -2031,7 +2014,7 @@ def report_invalid_syntax(self):
20312014
else:
20322015
offset = (1, 0)
20332016
self.report_error(offset[0], offset[1] or 0,
2034-
'E901 %s: %s' % (exc_type.__name__, exc.args[0]),
2017+
f'E901 {exc_type.__name__}: {exc.args[0]}',
20352018
self.report_invalid_syntax)
20362019

20372020
def readline(self):
@@ -2224,7 +2207,7 @@ def check_all(self, expected=None, line_offset=0):
22242207
token_type, text = token[0:2]
22252208
if self.verbose >= 3:
22262209
if token[2][0] == token[3][0]:
2227-
pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
2210+
pos = '[{}:{}]'.format(token[2][1] or '', token[3][1])
22282211
else:
22292212
pos = 'l.%s' % token[3][0]
22302213
print('l.%s\t%s\t%s\t%r' %
@@ -2251,7 +2234,7 @@ def check_all(self, expected=None, line_offset=0):
22512234
return self.report.get_file_results()
22522235

22532236

2254-
class BaseReport(object):
2237+
class BaseReport:
22552238
"""Collect the results of the checks."""
22562239

22572240
print_filename = False
@@ -2333,7 +2316,7 @@ def print_statistics(self, prefix=''):
23332316

23342317
def print_benchmark(self):
23352318
"""Print benchmark numbers."""
2336-
print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
2319+
print('{:<7.2f} {}'.format(self.elapsed, 'seconds elapsed'))
23372320
if self.elapsed:
23382321
for key in self._benchmark_keys:
23392322
print('%-7d %s per second (%d total)' %
@@ -2351,7 +2334,7 @@ class StandardReport(BaseReport):
23512334
"""Collect and print the results of the checks."""
23522335

23532336
def __init__(self, options):
2354-
super(StandardReport, self).__init__(options)
2337+
super().__init__(options)
23552338
self._fmt = REPORT_FORMAT.get(options.format.lower(),
23562339
options.format)
23572340
self._repeat = options.repeat
@@ -2361,13 +2344,12 @@ def __init__(self, options):
23612344
def init_file(self, filename, lines, expected, line_offset):
23622345
"""Signal a new file."""
23632346
self._deferred_print = []
2364-
return super(StandardReport, self).init_file(
2347+
return super().init_file(
23652348
filename, lines, expected, line_offset)
23662349

23672350
def error(self, line_number, offset, text, check):
23682351
"""Report an error, according to options."""
2369-
code = super(StandardReport, self).error(line_number, offset,
2370-
text, check)
2352+
code = super().error(line_number, offset, text, check)
23712353
if code and (self.counters[code] == 1 or self._repeat):
23722354
self._deferred_print.append(
23732355
(line_number, offset, code, text[5:], check.__doc__))
@@ -2406,16 +2388,16 @@ class DiffReport(StandardReport):
24062388
"""Collect and print the results for the changed lines only."""
24072389

24082390
def __init__(self, options):
2409-
super(DiffReport, self).__init__(options)
2391+
super().__init__(options)
24102392
self._selected = options.selected_lines
24112393

24122394
def error(self, line_number, offset, text, check):
24132395
if line_number not in self._selected[self.filename]:
24142396
return
2415-
return super(DiffReport, self).error(line_number, offset, text, check)
2397+
return super().error(line_number, offset, text, check)
24162398

24172399

2418-
class StyleGuide(object):
2400+
class StyleGuide:
24192401
"""Initialize a PEP-8 instance with few options."""
24202402

24212403
def __init__(self, *args, **kwargs):
@@ -2505,8 +2487,10 @@ def input_dir(self, dirname):
25052487
dirs.remove(subdir)
25062488
for filename in sorted(files):
25072489
# contain a pattern that matches?
2508-
if ((filename_match(filename, filepatterns) and
2509-
not self.excluded(filename, root))):
2490+
if (
2491+
filename_match(filename, filepatterns) and
2492+
not self.excluded(filename, root)
2493+
):
25102494
runner(os.path.join(root, filename))
25112495

25122496
def excluded(self, filename, parent=None):
@@ -2676,8 +2660,8 @@ def read_config(options, args, arglist, parser):
26762660
print(" unknown option '%s' ignored" % opt)
26772661
continue
26782662
if options.verbose > 1:
2679-
print(" %s = %s" % (opt,
2680-
config.get(pycodestyle_section, opt)))
2663+
print(" {} = {}".format(opt,
2664+
config.get(pycodestyle_section, opt)))
26812665
normalized_opt = opt.replace('-', '_')
26822666
opt_type = option_list[normalized_opt]
26832667
if opt_type in ('int', 'count'):

setup.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
from setuptools import setup
32

43

@@ -30,14 +29,9 @@ def get_long_description():
3029
url='https://pycodestyle.pycqa.org/',
3130
license='Expat license',
3231
py_modules=['pycodestyle'],
33-
namespace_packages=[],
3432
include_package_data=True,
3533
zip_safe=False,
36-
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
37-
install_requires=[
38-
# Broken with Python 3: https://github.com/pypa/pip/issues/650
39-
# 'setuptools',
40-
],
34+
python_requires='>=3.6',
4135
entry_points={
4236
'console_scripts': [
4337
'pycodestyle = pycodestyle:_main',
@@ -50,10 +44,7 @@ def get_long_description():
5044
'License :: OSI Approved :: MIT License',
5145
'Operating System :: OS Independent',
5246
'Programming Language :: Python',
53-
'Programming Language :: Python :: 2',
54-
'Programming Language :: Python :: 2.7',
5547
'Programming Language :: Python :: 3',
56-
'Programming Language :: Python :: 3.5',
5748
'Programming Language :: Python :: 3.6',
5849
'Programming Language :: Python :: 3.7',
5950
'Programming Language :: Python :: 3.8',

0 commit comments

Comments
 (0)