Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Drop support for Python 3.5 #510

Merged
merged 4 commits into from Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
python-version: [3.5, 3.6, 3.7, 3.8, 3.9-dev]
python-version: [3.6, 3.7, 3.8, 3.9-dev]

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -22,7 +22,7 @@ docstring conventions.
`PEP 257 <http://www.python.org/dev/peps/pep-0257/>`_ out of the box, but it
should not be considered a reference implementation.

**pydocstyle** supports Python 3.5, 3.6, 3.7 and 3.8.
**pydocstyle** supports Python 3.6, 3.7 and 3.8.


Quick Start
Expand Down
2 changes: 0 additions & 2 deletions docs/conf.py
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
#
# pydocstyle documentation build configuration file, created by
# sphinx-quickstart on Fri Jan 30 20:30:42 2015.
#
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Expand Up @@ -8,7 +8,7 @@ docstring conventions.
`PEP 257 <http://www.python.org/dev/peps/pep-0257/>`_ out of the box, but it
should not be considered a reference implementation.

**pydocstyle** supports Python 3.5, 3.6, 3.7 and 3.8.
**pydocstyle** supports Python 3.6, 3.7 and 3.8.


.. include:: quickstart.rst
Expand Down
4 changes: 4 additions & 0 deletions docs/release_notes.rst
Expand Up @@ -8,6 +8,10 @@ Release Notes
Current Development Version
---------------------------

Major Updates

* Support for Python 3.5 has been dropped (#510).

New Features

* Add flag to disable `# noqa` comment processing in API (#485).
Expand Down
7 changes: 3 additions & 4 deletions setup.py
@@ -1,5 +1,4 @@
from setuptools import setup
import sys

# Do not update the version manually - it is managed by `bumpversion`.
version = '5.1.2rc'
Expand All @@ -24,14 +23,14 @@
'Environment :: Console',
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3 :: Only',
'Operating System :: OS Independent',
'License :: OSI Approved :: MIT License',
],
python_requires='>=3.5',
python_requires='>=3.6',
keywords='pydocstyle, PEP 257, pep257, PEP 8, pep8, docstrings',
packages=('pydocstyle',),
package_dir={'': 'src'},
Expand All @@ -43,6 +42,6 @@
],
},
project_urls={
'Release Notes': 'http://www.pydocstyle.org/en/latest/release_notes.html',
'Release Notes': 'https://www.pydocstyle.org/en/latest/release_notes.html',
},
)
27 changes: 2 additions & 25 deletions src/pydocstyle/checker.py
Expand Up @@ -385,23 +385,6 @@ def check_backslashes(self, definition, docstring):
and not docstring.startswith(('r', 'ur'))):
return violations.D301()

@check_for(Definition)
def check_unicode_docstring(self, definition, docstring):
r'''D302: Use u""" for docstrings with Unicode.

For Unicode docstrings, use u"""Unicode triple-quoted strings""".

'''
if 'unicode_literals' in definition.module.future_imports:
return

# Just check that docstring is unicode, check_triple_double_quotes
# ensures the correct quotes.
if docstring and sys.version_info[0] <= 2:
if not is_ascii(docstring) and not docstring.startswith(
('u', 'ur')):
return violations.D302()

@staticmethod
def _check_ends_with(docstring, chars, violation):
"""First line ends with one of `chars`.
Expand Down Expand Up @@ -453,13 +436,7 @@ def check_imperative_mood(self, function, docstring): # def context
if check_word in IMPERATIVE_BLACKLIST:
return violations.D401b(first_word)

try:
correct_forms = IMPERATIVE_VERBS.get(stem(check_word))
except UnicodeDecodeError:
# This is raised when the docstring contains unicode
# characters in the first word, but is not a unicode
# string. In which case D302 will be reported. Ignoring.
return
correct_forms = IMPERATIVE_VERBS.get(stem(check_word))

if correct_forms and check_word not in correct_forms:
best = max(
Expand Down Expand Up @@ -985,7 +962,7 @@ def check(filenames, select=None, ignore=None, ignore_decorators=None, ignore_in
code = getattr(error, 'code', None)
if code in checked_codes:
yield error
except (EnvironmentError, AllError, ParseError) as error:
except (OSError, AllError, ParseError) as error:
log.warning('Error in file %s: %s', filename, error)
yield error
except tk.TokenError:
Expand Down
8 changes: 4 additions & 4 deletions src/pydocstyle/config.py
Expand Up @@ -316,7 +316,7 @@ def _read_configuration_file(self, path):
continue

if opt.replace('_', '-') not in self.CONFIG_FILE_OPTIONS:
log.warning("Unknown option '{}' ignored".format(opt))
log.warning(f"Unknown option '{opt}' ignored")
continue

normalized_opt = opt.replace('-', '_')
Expand All @@ -335,7 +335,7 @@ def _read_configuration_file(self, path):

if options is not None:
if not self._validate_options(options):
raise IllegalConfiguration('in file: {}'.format(path))
raise IllegalConfiguration(f'in file: {path}')

return options, should_inherit

Expand Down Expand Up @@ -388,7 +388,7 @@ def _create_check_config(cls, options, use_defaults=True):

kwargs = dict(checked_codes=checked_codes)
for key in ('match', 'match_dir', 'ignore_decorators'):
kwargs[key] = getattr(cls, 'DEFAULT_{}_RE'.format(key.upper())) \
kwargs[key] = getattr(cls, f'DEFAULT_{key.upper()}_RE') \
if getattr(options, key) is None and use_defaults \
else getattr(options, key)
return CheckConfiguration(**kwargs)
Expand Down Expand Up @@ -521,7 +521,7 @@ def _get_set(value_str):

"""
return cls._expand_error_codes(
set([x.strip() for x in value_str.split(",")]) - {""}
{x.strip() for x in value_str.split(",")} - {""}
)

for opt in optional_set_options:
Expand Down
13 changes: 6 additions & 7 deletions src/pydocstyle/parser.py
Expand Up @@ -55,7 +55,7 @@ def __eq__(self, other):
def __repr__(self):
kwargs = ', '.join('{}={!r}'.format(field, getattr(self, field))
for field in self._fields)
return '{}({})'.format(self.__class__.__name__, kwargs)
return f'{self.__class__.__name__}({kwargs})'


class Definition(Value):
Expand Down Expand Up @@ -97,9 +97,9 @@ def is_empty_or_comment(line):
return ''.join(reversed(list(filtered_src)))

def __str__(self):
out = 'in {} {} `{}`'.format(self._publicity, self._human, self.name)
out = f'in {self._publicity} {self._human} `{self.name}`'
if self.skipped_error_codes:
out += ' (skipping {})'.format(self.skipped_error_codes)
out += f' (skipping {self.skipped_error_codes})'
return out


Expand Down Expand Up @@ -211,7 +211,7 @@ def is_public(self):
# Check if we are a setter/deleter method, and mark as private if so.
for decorator in self.decorators:
# Given 'foo', match 'foo.bar' but not 'foobar' or 'sfoo'
if re(r"^{}\.".format(self.name)).match(decorator.name):
if re(fr"^{self.name}\.").match(decorator.name):
return False
name_is_public = (not self.name.startswith('_') or
self.name in VARIADIC_MAGIC_METHODS or
Expand Down Expand Up @@ -343,7 +343,7 @@ def __init__(self, *args):
self.kind = TokenKind(self.kind)

def __str__(self):
return "{!r} ({})".format(self.kind, self.value)
return f"{self.kind!r} ({self.value})"


class Parser:
Expand Down Expand Up @@ -472,8 +472,7 @@ def parse_definitions(self, class_, dunder_all=False):
yield self.parse_definition(class_._nest(self.current.value))
elif self.current.kind == tk.INDENT:
self.consume(tk.INDENT)
for definition in self.parse_definitions(class_):
yield definition
yield from self.parse_definitions(class_)
elif self.current.kind == tk.DEDENT:
self.consume(tk.DEDENT)
return
Expand Down
10 changes: 5 additions & 5 deletions src/pydocstyle/violations.py
Expand Up @@ -52,10 +52,10 @@ def set_context(self, definition: Definition, explanation: str) -> None:
@property
def message(self) -> str:
"""Return the message to print to the user."""
ret = '{}: {}'.format(self.code, self.short_desc)
ret = f'{self.code}: {self.short_desc}'
if self.context is not None:
specific_error_msg = self.context.format(*self.parameters)
ret += ' ({})'.format(specific_error_msg)
ret += f' ({specific_error_msg})'
return ret

@property
Expand All @@ -69,7 +69,7 @@ def lines(self) -> str:
lines_stripped = list(reversed(list(dropwhile(is_blank,
reversed(lines)))))
numbers_width = len(str(offset + len(lines_stripped)))
line_format = '{{:{}}}:{{}}'.format(numbers_width)
line_format = f'{{:{numbers_width}}}:{{}}'
for n, line in enumerate(lines_stripped):
if line:
line = ' ' + line
Expand Down Expand Up @@ -159,7 +159,7 @@ def to_rst(cls) -> str:
for group in cls.groups:
table += sep_line
table += blank_line
table += '|' + '**{}**'.format(group.name).center(max_len + 9) + '|\n'
table += '|' + f'**{group.name}**'.center(max_len + 9) + '|\n'
table += blank_line
for error in group.errors:
table += sep_line
Expand Down Expand Up @@ -214,7 +214,7 @@ def to_rst(cls) -> str:
D300 = D3xx.create_error('D300', 'Use """triple double quotes"""',
'found {0}-quotes')
D301 = D3xx.create_error('D301', 'Use r""" if any backslashes in a docstring')
D302 = D3xx.create_error('D302', 'Use u""" for Unicode docstrings')
D302 = D3xx.create_error('D302', 'Deprecated: Use u""" for Unicode docstrings')

D4xx = ErrorRegistry.create_group('D4', 'Docstring Content Issues')
D400 = D4xx.create_error('D400', 'First line should end with a period',
Expand Down
8 changes: 0 additions & 8 deletions src/tests/parser_test.py
Expand Up @@ -52,10 +52,6 @@ def do_something(pos_param0, pos_param1, kw_param0="default"):

def test_simple_fstring():
"""Test parsing of a function with a simple fstring as a docstring."""
# fstrings are not supported in Python 3.5
if sys.version_info[0:2] == (3, 5):
return

parser = Parser()
code = CodeSnippet("""\
def do_something(pos_param0, pos_param1, kw_param0="default"):
Expand Down Expand Up @@ -85,10 +81,6 @@ def do_something(pos_param0, pos_param1, kw_param0="default"):

def test_fstring_with_args():
"""Test parsing of a function with an fstring with args as a docstring."""
# fstrings are not supported in Python 3.5
if sys.version_info[0:2] == (3, 5):
return

parser = Parser()
code = CodeSnippet("""\
foo = "bar"
Expand Down
2 changes: 1 addition & 1 deletion src/tests/test_cases/canonical_google_examples.py
Expand Up @@ -83,7 +83,7 @@ def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"('Attributes', not 'Attributes:')")
@expect("D407: Missing dashed underline after section ('Attributes')")
@expect("D413: Missing blank line after last section ('Attributes')")
class SampleClass(object):
class SampleClass:
"""Summary of class here.

Longer class information....
Expand Down
1 change: 0 additions & 1 deletion src/tests/test_cases/noqa.py
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# noqa: D400,D415
"""Test case for "# noqa" comments"""
from .expected import Expectation
Expand Down
11 changes: 0 additions & 11 deletions src/tests/test_cases/test.py
@@ -1,4 +1,3 @@
# encoding: utf-8
# No docstring, so we can test D100
from functools import wraps
import os
Expand Down Expand Up @@ -280,16 +279,6 @@ def exceptions_of_D301():
"""


if sys.version_info[0] <= 2:
@expect('D302: Use u""" for Unicode docstrings')
def unicode_unmarked():
"""Юникод."""

@expect('D302: Use u""" for Unicode docstrings')
def first_word_has_unicode_byte():
"""あy."""


@expect("D400: First line should end with a period (not 'y')")
@expect("D415: First line should end with a period, question mark, "
"or exclamation point (not 'y')")
Expand Down
2 changes: 0 additions & 2 deletions src/tests/test_cases/unicode_literals.py
@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
"""A module."""

from __future__ import unicode_literals
from .expected import Expectation


Expand Down
2 changes: 1 addition & 1 deletion src/tests/test_definitions.py
Expand Up @@ -26,7 +26,7 @@
])
def test_complex_file(test_case):
"""Run domain-specific tests from test.py file."""
case_module = __import__('test_cases.{}'.format(test_case),
case_module = __import__(f'test_cases.{test_case}',
globals=globals(),
locals=locals(),
fromlist=['expectation'],
Expand Down
7 changes: 2 additions & 5 deletions src/tests/test_integration.py
@@ -1,8 +1,5 @@
# -*- coding: utf-8 -*-

"""Use tox or py.test to run the test-suite."""

from __future__ import with_statement
from collections import namedtuple

import os
Expand Down Expand Up @@ -52,7 +49,7 @@ def write_config(self, prefix='', name='tox.ini', **kwargs):
self.makedirs(base)

with open(os.path.join(base, name), 'wt') as conf:
conf.write("[{}]\n".format(self.script_name))
conf.write(f"[{self.script_name}]\n")
for k, v in kwargs.items():
conf.write("{} = {}\n".format(k.replace('_', '-'), v))

Expand Down Expand Up @@ -284,7 +281,7 @@ def test_sectionless_config_file(env):
conf.write('[pdcstl]')
config_path = conf.name

_, err, code = env.invoke('--config={}'.format(config_path))
_, err, code = env.invoke(f'--config={config_path}')
assert code == 0
assert 'Configuration file does not contain a pydocstyle section' in err

Expand Down
10 changes: 5 additions & 5 deletions tox.ini
Expand Up @@ -4,7 +4,7 @@
# install tox" and then run "tox" from this directory.

[tox]
envlist = {py35,py36,py37,py38,py39}-{tests,install},docs,install,py36-docs
envlist = {py36,py37,py38,py39}-{tests,install},docs,install,py36-docs

[testenv]
download = true
Expand Down Expand Up @@ -42,10 +42,6 @@ commands = {[testenv:docs]commands}
# There's no way to generate sub-sections in tox.
# The following sections are all references to the `py37-install`.

[testenv:py35-install]
skip_install = {[testenv:install]skip_install}
commands = {[testenv:install]commands}

[testenv:py36-install]
skip_install = {[testenv:install]skip_install}
commands = {[testenv:install]commands}
Expand All @@ -58,6 +54,10 @@ commands = {[testenv:install]commands}
skip_install = {[testenv:install]skip_install}
commands = {[testenv:install]commands}

[testenv:py39-install]
skip_install = {[testenv:install]skip_install}
commands = {[testenv:install]commands}

[pytest]
pep8ignore =
test.py E701 E704
Expand Down