pycodestyle 2.12.1__tar.gz → 2.14.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/PKG-INFO +2 -3
  2. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.egg-info/PKG-INFO +2 -3
  3. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.py +62 -29
  4. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/setup.cfg +1 -2
  5. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_E901.py +2 -2
  6. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/LICENSE +0 -0
  7. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/README.rst +0 -0
  8. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.egg-info/SOURCES.txt +0 -0
  9. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.egg-info/dependency_links.txt +0 -0
  10. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.egg-info/entry_points.txt +0 -0
  11. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.egg-info/not-zip-safe +0 -0
  12. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/pycodestyle.egg-info/top_level.txt +0 -0
  13. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/setup.py +0 -0
  14. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_E101.py +0 -0
  15. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_all.py +0 -0
  16. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_api.py +0 -0
  17. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_blank_lines.py +0 -0
  18. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_data.py +0 -0
  19. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_parser.py +0 -0
  20. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_pycodestyle.py +0 -0
  21. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_self_doctests.py +0 -0
  22. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_shell.py +0 -0
  23. {pycodestyle-2.12.1 → pycodestyle-2.14.0}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycodestyle
3
- Version: 2.12.1
3
+ Version: 2.14.0
4
4
  Summary: Python style guide checker
5
5
  Home-page: https://pycodestyle.pycqa.org/
6
6
  Author: Johann C. Rocholl
@@ -13,7 +13,6 @@ Keywords: pycodestyle,pep8,PEP 8,PEP-8,PEP8
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Environment :: Console
15
15
  Classifier: Intended Audience :: Developers
16
- Classifier: License :: OSI Approved :: MIT License
17
16
  Classifier: Operating System :: OS Independent
18
17
  Classifier: Programming Language :: Python
19
18
  Classifier: Programming Language :: Python :: 3
@@ -21,7 +20,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
21
20
  Classifier: Programming Language :: Python :: Implementation :: CPython
22
21
  Classifier: Programming Language :: Python :: Implementation :: PyPy
23
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
- Requires-Python: >=3.8
23
+ Requires-Python: >=3.9
25
24
  Description-Content-Type: text/x-rst
26
25
  License-File: LICENSE
27
26
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycodestyle
3
- Version: 2.12.1
3
+ Version: 2.14.0
4
4
  Summary: Python style guide checker
5
5
  Home-page: https://pycodestyle.pycqa.org/
6
6
  Author: Johann C. Rocholl
@@ -13,7 +13,6 @@ Keywords: pycodestyle,pep8,PEP 8,PEP-8,PEP8
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Environment :: Console
15
15
  Classifier: Intended Audience :: Developers
16
- Classifier: License :: OSI Approved :: MIT License
17
16
  Classifier: Operating System :: OS Independent
18
17
  Classifier: Programming Language :: Python
19
18
  Classifier: Programming Language :: Python :: 3
@@ -21,7 +20,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
21
20
  Classifier: Programming Language :: Python :: Implementation :: CPython
22
21
  Classifier: Programming Language :: Python :: Implementation :: PyPy
23
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
- Requires-Python: >=3.8
23
+ Requires-Python: >=3.9
25
24
  Description-Content-Type: text/x-rst
26
25
  License-File: LICENSE
27
26
 
@@ -68,7 +68,7 @@ if (
68
68
  ): # pragma: no cover (<py310)
69
69
  tokenize._compile = lru_cache(tokenize._compile) # type: ignore
70
70
 
71
- __version__ = '2.12.1'
71
+ __version__ = '2.14.0'
72
72
 
73
73
  DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
74
74
  DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
@@ -135,6 +135,7 @@ OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)')
135
135
  LAMBDA_REGEX = re.compile(r'\blambda\b')
136
136
  HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
137
137
  STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b')
138
+ STARTSWITH_GENERIC_REGEX = re.compile(r'^(async\s+def|def|class|type)\s+\w+\[')
138
139
  STARTSWITH_TOP_LEVEL_REGEX = re.compile(r'^(async\s+def\s+|def\s+|class\s+|@)')
139
140
  STARTSWITH_INDENT_STATEMENT_REGEX = re.compile(
140
141
  r'^\s*({})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
@@ -157,6 +158,13 @@ if sys.version_info >= (3, 12): # pragma: >=3.12 cover
157
158
  else: # pragma: <3.12 cover
158
159
  FSTRING_START = FSTRING_MIDDLE = FSTRING_END = -1
159
160
 
161
+ if sys.version_info >= (3, 14): # pragma: >=3.14 cover
162
+ TSTRING_START = tokenize.TSTRING_START
163
+ TSTRING_MIDDLE = tokenize.TSTRING_MIDDLE
164
+ TSTRING_END = tokenize.TSTRING_END
165
+ else: # pragma: <3.14 cover
166
+ TSTRING_START = TSTRING_MIDDLE = TSTRING_END = -1
167
+
160
168
  _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
161
169
 
162
170
 
@@ -233,9 +241,11 @@ def trailing_whitespace(physical_line):
233
241
  W291: spam(1) \n#
234
242
  W293: class Foo(object):\n \n bang = 12
235
243
  """
236
- physical_line = physical_line.rstrip('\n') # chr(10), newline
237
- physical_line = physical_line.rstrip('\r') # chr(13), carriage return
238
- physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
244
+ # Strip these trailing characters:
245
+ # - chr(10), newline
246
+ # - chr(13), carriage return
247
+ # - chr(12), form feed, ^L
248
+ physical_line = physical_line.rstrip('\n\r\x0c')
239
249
  stripped = physical_line.rstrip(' \t\v')
240
250
  if physical_line != stripped:
241
251
  if stripped:
@@ -694,7 +704,12 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
694
704
  if verbose >= 4:
695
705
  print(f"bracket depth {depth} indent to {start[1]}")
696
706
  # deal with implicit string concatenation
697
- elif token_type in (tokenize.STRING, tokenize.COMMENT, FSTRING_START):
707
+ elif token_type in {
708
+ tokenize.STRING,
709
+ tokenize.COMMENT,
710
+ FSTRING_START,
711
+ TSTRING_START
712
+ }:
698
713
  indent_chances[start[1]] = str
699
714
  # visual indent after assert/raise/with
700
715
  elif not row and not depth and text in ["assert", "raise", "with"]:
@@ -783,7 +798,6 @@ def whitespace_before_parameters(logical_line, tokens):
783
798
  # Allow "return (a.foo for a in range(5))"
784
799
  not keyword.iskeyword(prev_text) and
785
800
  (
786
- sys.version_info < (3, 9) or
787
801
  # 3.12+: type is a soft keyword but no braces after
788
802
  prev_text == 'type' or
789
803
  not keyword.issoftkeyword(prev_text)
@@ -871,6 +885,8 @@ def missing_whitespace(logical_line, tokens):
871
885
  brace_stack.append(text)
872
886
  elif token_type == FSTRING_START: # pragma: >=3.12 cover
873
887
  brace_stack.append('f')
888
+ elif token_type == TSTRING_START: # pragma: >=3.14 cover
889
+ brace_stack.append('t')
874
890
  elif token_type == tokenize.NAME and text == 'lambda':
875
891
  brace_stack.append('l')
876
892
  elif brace_stack:
@@ -878,6 +894,8 @@ def missing_whitespace(logical_line, tokens):
878
894
  brace_stack.pop()
879
895
  elif token_type == FSTRING_END: # pragma: >=3.12 cover
880
896
  brace_stack.pop()
897
+ elif token_type == TSTRING_END: # pragma: >=3.14 cover
898
+ brace_stack.pop()
881
899
  elif (
882
900
  brace_stack[-1] == 'l' and
883
901
  token_type == tokenize.OP and
@@ -897,6 +915,9 @@ def missing_whitespace(logical_line, tokens):
897
915
  # 3.12+ fstring format specifier
898
916
  elif text == ':' and brace_stack[-2:] == ['f', '{']: # pragma: >=3.12 cover # noqa: E501
899
917
  pass
918
+ # 3.14+ tstring format specifier
919
+ elif text == ':' and brace_stack[-2:] == ['t', '{']: # pragma: >=3.14 cover # noqa: E501
920
+ pass
900
921
  # tuple (and list for some reason?)
901
922
  elif text == ',' and next_char in ')]':
902
923
  pass
@@ -946,7 +967,9 @@ def missing_whitespace(logical_line, tokens):
946
967
  # allow keyword args or defaults: foo(bar=None).
947
968
  brace_stack[-1:] == ['('] or
948
969
  # allow python 3.8 fstring repr specifier
949
- brace_stack[-2:] == ['f', '{']
970
+ brace_stack[-2:] == ['f', '{'] or
971
+ # allow python 3.8 fstring repr specifier
972
+ brace_stack[-2:] == ['t', '{']
950
973
  )
951
974
  ):
952
975
  pass
@@ -958,10 +981,8 @@ def missing_whitespace(logical_line, tokens):
958
981
  # Allow argument unpacking: foo(*args, **kwargs).
959
982
  if prev_type == tokenize.OP and prev_text in '}])' or (
960
983
  prev_type != tokenize.OP and
961
- prev_text not in KEYWORDS and (
962
- sys.version_info < (3, 9) or
963
- not keyword.issoftkeyword(prev_text)
964
- )
984
+ prev_text not in KEYWORDS and
985
+ not keyword.issoftkeyword(prev_text)
965
986
  ):
966
987
  need_space = None
967
988
  elif text in WS_OPTIONAL_OPERATORS:
@@ -1020,12 +1041,13 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
1020
1041
  E251: return magic(r = real, i = imag)
1021
1042
  E252: def complex(real, image: float=0.0):
1022
1043
  """
1023
- parens = 0
1044
+ paren_stack = []
1024
1045
  no_space = False
1025
1046
  require_space = False
1026
1047
  prev_end = None
1027
1048
  annotated_func_arg = False
1028
1049
  in_def = bool(STARTSWITH_DEF_REGEX.match(logical_line))
1050
+ in_generic = bool(STARTSWITH_GENERIC_REGEX.match(logical_line))
1029
1051
 
1030
1052
  message = "E251 unexpected spaces around keyword / parameter equals"
1031
1053
  missing_message = "E252 missing whitespace around parameter equals"
@@ -1043,15 +1065,23 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
1043
1065
  yield (prev_end, missing_message)
1044
1066
  if token_type == tokenize.OP:
1045
1067
  if text in '([':
1046
- parens += 1
1047
- elif text in ')]':
1048
- parens -= 1
1049
- elif in_def and text == ':' and parens == 1:
1068
+ paren_stack.append(text)
1069
+ elif text in ')]' and paren_stack:
1070
+ paren_stack.pop()
1071
+ # def f(arg: tp = default): ...
1072
+ elif text == ':' and in_def and paren_stack == ['(']:
1050
1073
  annotated_func_arg = True
1051
- elif parens == 1 and text == ',':
1074
+ elif len(paren_stack) == 1 and text == ',':
1052
1075
  annotated_func_arg = False
1053
- elif parens and text == '=':
1054
- if annotated_func_arg and parens == 1:
1076
+ elif paren_stack and text == '=':
1077
+ if (
1078
+ # PEP 696 defaults always use spaced-style `=`
1079
+ # type A[T = default] = ...
1080
+ # def f[T = default](): ...
1081
+ # class C[T = default](): ...
1082
+ (in_generic and paren_stack == ['[']) or
1083
+ (annotated_func_arg and paren_stack == ['('])
1084
+ ):
1055
1085
  require_space = True
1056
1086
  if start == prev_end:
1057
1087
  yield (prev_end, missing_message)
@@ -1059,7 +1089,7 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
1059
1089
  no_space = True
1060
1090
  if start != prev_end:
1061
1091
  yield (prev_end, message)
1062
- if not parens:
1092
+ if not paren_stack:
1063
1093
  annotated_func_arg = False
1064
1094
 
1065
1095
  prev_end = end
@@ -1631,11 +1661,11 @@ def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
1631
1661
 
1632
1662
  prefixes = []
1633
1663
  for token_type, text, start, _, _ in tokens:
1634
- if token_type in {tokenize.STRING, FSTRING_START}:
1664
+ if token_type in {tokenize.STRING, FSTRING_START, TSTRING_START}:
1635
1665
  # Extract string modifiers (e.g. u or r)
1636
1666
  prefixes.append(text[:text.index(text[-1])].lower())
1637
1667
 
1638
- if token_type in {tokenize.STRING, FSTRING_MIDDLE}:
1668
+ if token_type in {tokenize.STRING, FSTRING_MIDDLE, TSTRING_MIDDLE}:
1639
1669
  if 'r' not in prefixes[-1]:
1640
1670
  start_line, start_col = start
1641
1671
  pos = text.find('\\')
@@ -1653,7 +1683,7 @@ def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
1653
1683
  )
1654
1684
  pos = text.find('\\', pos + 1)
1655
1685
 
1656
- if token_type in {tokenize.STRING, FSTRING_END}:
1686
+ if token_type in {tokenize.STRING, FSTRING_END, TSTRING_END}:
1657
1687
  prefixes.pop()
1658
1688
 
1659
1689
 
@@ -1851,7 +1881,7 @@ class Checker:
1851
1881
  self.max_line_length = options.max_line_length
1852
1882
  self.max_doc_length = options.max_doc_length
1853
1883
  self.indent_size = options.indent_size
1854
- self.fstring_start = 0
1884
+ self.fstring_start = self.tstring_start = 0
1855
1885
  self.multiline = False # in a multiline string?
1856
1886
  self.hang_closing = options.hang_closing
1857
1887
  self.indent_size = options.indent_size
@@ -1910,9 +1940,7 @@ class Checker:
1910
1940
 
1911
1941
  def run_check(self, check, argument_names):
1912
1942
  """Run a check plugin."""
1913
- arguments = []
1914
- for name in argument_names:
1915
- arguments.append(getattr(self, name))
1943
+ arguments = [getattr(self, name) for name in argument_names]
1916
1944
  return check(*arguments)
1917
1945
 
1918
1946
  def init_checker_state(self, name, argument_names):
@@ -1948,7 +1976,7 @@ class Checker:
1948
1976
  continue
1949
1977
  if token_type == tokenize.STRING:
1950
1978
  text = mute_string(text)
1951
- elif token_type == FSTRING_MIDDLE: # pragma: >=3.12 cover
1979
+ elif token_type in {FSTRING_MIDDLE, TSTRING_MIDDLE}: # pragma: >=3.12 cover # noqa: E501
1952
1980
  # fstring tokens are "unescaped" braces -- re-escape!
1953
1981
  brace_count = text.count('{') + text.count('}')
1954
1982
  text = 'x' * (len(text) + brace_count)
@@ -2040,6 +2068,8 @@ class Checker:
2040
2068
 
2041
2069
  if token.type == FSTRING_START: # pragma: >=3.12 cover
2042
2070
  self.fstring_start = token.start[0]
2071
+ elif token.type == TSTRING_START: # pragma: >=3.14 cover
2072
+ self.tstring_start = token.start[0]
2043
2073
  # a newline token ends a single physical line.
2044
2074
  elif _is_eol_token(token):
2045
2075
  # if the file does not end with a newline, the NEWLINE
@@ -2051,7 +2081,8 @@ class Checker:
2051
2081
  self.check_physical(token.line)
2052
2082
  elif (
2053
2083
  token.type == tokenize.STRING and '\n' in token.string or
2054
- token.type == FSTRING_END
2084
+ token.type == FSTRING_END or
2085
+ token.type == TSTRING_END
2055
2086
  ):
2056
2087
  # Less obviously, a string that contains newlines is a
2057
2088
  # multiline string, either triple-quoted or with internal
@@ -2072,6 +2103,8 @@ class Checker:
2072
2103
  return
2073
2104
  if token.type == FSTRING_END: # pragma: >=3.12 cover
2074
2105
  start = self.fstring_start
2106
+ elif token.type == TSTRING_END: # pragma: >=3.12 cover
2107
+ start = self.tstring_start
2075
2108
  else:
2076
2109
  start = token.start[0]
2077
2110
  end = token.end[0]
@@ -15,7 +15,6 @@ classifiers =
15
15
  Development Status :: 5 - Production/Stable
16
16
  Environment :: Console
17
17
  Intended Audience :: Developers
18
- License :: OSI Approved :: MIT License
19
18
  Operating System :: OS Independent
20
19
  Programming Language :: Python
21
20
  Programming Language :: Python :: 3
@@ -29,7 +28,7 @@ project_urls =
29
28
 
30
29
  [options]
31
30
  py_modules = pycodestyle
32
- python_requires = >=3.8
31
+ python_requires = >=3.9
33
32
  include_package_data = True
34
33
  zip_safe = False
35
34
 
@@ -23,7 +23,7 @@ def lasting(self, duration=300):
23
23
  '''
24
24
  errors = errors_from_src(src)
25
25
  if sys.version_info < (3, 12): # pragma: <3.12 cover
26
- expected = ['E122:4:1', 'E251:5:13', 'E251:5:15']
26
+ expected = ['E122:4:1']
27
27
  else: # pragma: >=3.12 cover
28
- expected = ['E122:4:1', 'E251:5:13', 'E251:5:15', 'E901:5:1'] # noqa: E501
28
+ expected = ['E122:4:1', 'E901:5:1'] # noqa: E501
29
29
  self.assertEqual(errors, expected)
File without changes
File without changes
File without changes