Hello community,
here is the log from the commit of package python-pydocstyle for
openSUSE:Factory checked in at 2020-10-29 09:47:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pydocstyle (Old)
and /work/SRC/openSUSE:Factory/.python-pydocstyle.new.3463 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pydocstyle"
Thu Oct 29 09:47:24 2020 rev:9 rq:841138 version:5.1.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pydocstyle/python-pydocstyle.changes
2020-05-28 09:08:18.431874660 +0200
+++
/work/SRC/openSUSE:Factory/.python-pydocstyle.new.3463/python-pydocstyle.changes
2020-10-29 09:47:31.656124493 +0100
@@ -1,0 +2,22 @@
+Sat Oct 10 18:42:12 UTC 2020 - Arun Persaud <[email protected]>
+
+- update to version 5.1.1:
+ * Bug Fixes
+ + Fix IndexError crash on one-line backslashed docstrings (#506).
+
+- changes from version 5.1.0 :
+ * New Features
+ + Skip function arguments prefixed with _ in D417 check (#440).
+ * Bug Fixes
+ + Update convention support documentation (#386, #393)
+ + Detect inner asynchronous functions for D202 (#467)
+ + Fix indentation error while parsing class methods (#441).
+ + Fix a bug in parsing Google-style argument description. The bug
+ caused some argument names to go unreported in D417 (#448).
+ + Fixed an issue where skipping errors on module level docstring
+ via #noqa failed when there where more prior comments (#446).
+ + Support backslash-continued descriptions in docstrings (#472).
+ + Correctly detect publicity of modules inside directories (#470,
+ #494).
+
+-------------------------------------------------------------------
Old:
----
pydocstyle-5.0.2.tar.gz
New:
----
pydocstyle-5.1.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pydocstyle.spec ++++++
--- /var/tmp/diff_new_pack.lRRdcO/_old 2020-10-29 09:47:32.476125267 +0100
+++ /var/tmp/diff_new_pack.lRRdcO/_new 2020-10-29 09:47:32.476125267 +0100
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-pydocstyle
-Version: 5.0.2
+Version: 5.1.1
Release: 0
Summary: Python docstring style checker
License: MIT
++++++ pydocstyle-5.0.2.tar.gz -> pydocstyle-5.1.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/.appveyor.yml
new/pydocstyle-5.1.1/.appveyor.yml
--- old/pydocstyle-5.0.2/.appveyor.yml 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/.appveyor.yml 1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-environment:
- matrix:
- - TOXENV: "py35-tests"
- - TOXENV: "py35-install"
- - TOXENV: "py36-tests"
- - TOXENV: "py36-install"
- - TOXENV: "py37-tests"
- - TOXENV: "py37-install"
- - TOXENV: "py36-docs"
-
-install:
- - pip install tox
-
-build: off
-
-test_script:
- - tox -e %TOXENV%
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/.bumpversion.cfg
new/pydocstyle-5.1.1/.bumpversion.cfg
--- old/pydocstyle-5.0.2/.bumpversion.cfg 2020-01-08 13:37:01.000000000
+0100
+++ new/pydocstyle-5.1.1/.bumpversion.cfg 2020-08-29 22:52:53.000000000
+0200
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 5.0.2
+current_version = 5.1.1
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<release>.*))?
serialize =
@@ -16,4 +16,3 @@
[bumpversion:file:setup.py]
[bumpversion:file:src/pydocstyle/utils.py]
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/.github/workflows/test.yml
new/pydocstyle-5.1.1/.github/workflows/test.yml
--- old/pydocstyle-5.0.2/.github/workflows/test.yml 1970-01-01
01:00:00.000000000 +0100
+++ new/pydocstyle-5.1.1/.github/workflows/test.yml 2020-08-29
22:52:53.000000000 +0200
@@ -0,0 +1,22 @@
+name: Run tests
+
+on: [push, pull_request]
+
+jobs:
+ test-latest:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [macos-latest, ubuntu-latest, windows-latest]
+ python-version: [3.5, 3.6, 3.7, 3.8]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v1
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install tox
+ run: python -m pip install --upgrade pip tox
+ - name: Run Tests
+ run: tox -e py,install,docs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/.gitignore
new/pydocstyle-5.1.1/.gitignore
--- old/pydocstyle-5.0.2/.gitignore 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/.gitignore 2020-08-29 22:52:53.000000000 +0200
@@ -54,3 +54,6 @@
# PyCharm files
.idea
+
+# VS Code
+.vscode/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/.travis.yml
new/pydocstyle-5.1.1/.travis.yml
--- old/pydocstyle-5.0.2/.travis.yml 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/.travis.yml 1970-01-01 01:00:00.000000000 +0100
@@ -1,29 +0,0 @@
-# Travis (http://travis-ci.org/) is a continuous integration
-# service for open source projects. This file configures
-# Travis to install and run "tox" test runner, which is
-# configured in tox.ini file.
-
-sudo: false
-language: python
-install: pip install tox
-script: tox
-matrix:
- include:
- - python: 3.5
- env: TOXENV=py35-tests
- - python: 3.5
- env: TOXENV=py35-install
- - python: 3.6
- env: TOXENV=py36-tests
- - python: 3.6
- env: TOXENV=py36-install
- - python: 3.7
- env: TOXENV=py37-tests
- - python: 3.7
- env: TOXENV=py37-install
- - python: 3.8
- env: TOXENV=py38-tests
- - python: 3.8
- env: TOXENV=py38-install
- - python: 3.6
- env: TOXENV=docs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/README.rst
new/pydocstyle-5.1.1/README.rst
--- old/pydocstyle-5.0.2/README.rst 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/README.rst 2020-08-29 22:52:53.000000000 +0200
@@ -2,11 +2,8 @@
====================================
-.. image:: https://travis-ci.org/PyCQA/pydocstyle.svg?branch=master
- :target: https://travis-ci.org/PyCQA/pydocstyle
-
-.. image::
https://ci.appveyor.com/api/projects/status/40kkc366bmrrttca/branch/master?svg=true
- :target: https://ci.appveyor.com/project/Nurdok/pydocstyle/branch/master
+.. image:: https://github.com/PyCQA/pydocstyle/workflows/Run%20tests/badge.svg
+ :target:
https://github.com/PyCQA/pydocstyle/actions?query=workflow%3A%22Run+tests%22+branch%3Amaster
.. image:: https://readthedocs.org/projects/pydocstyle/badge/?version=latest
:target: https://readthedocs.org/projects/pydocstyle/?badge=latest
@@ -15,6 +12,8 @@
.. image:: https://img.shields.io/pypi/pyversions/pydocstyle.svg
:target: https://pypi.org/project/pydocstyle
+.. image:: https://pepy.tech/badge/pydocstyle
+ :target: https://pepy.tech/project/pydocstyle
**pydocstyle** is a static analysis tool for checking compliance with Python
docstring conventions.
@@ -55,7 +54,7 @@
Links
-----
-* `Read the full documentation here <http://pydocstyle.org>`_.
+* `Read the full documentation here <http://pydocstyle.org/en/stable/>`_.
* `Fork pydocstyle on GitHub <http://github.com/PyCQA/pydocstyle>`_.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/docs/conf.py
new/pydocstyle-5.1.1/docs/conf.py
--- old/pydocstyle-5.0.2/docs/conf.py 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/docs/conf.py 2020-08-29 22:52:53.000000000 +0200
@@ -58,7 +58,7 @@
# The short X.Y version.
version = pydocstyle.__version__
# The full version, including alpha/beta/rc tags.
-release = '1.0.0'
+release = pydocstyle.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/docs/error_codes.rst
new/pydocstyle-5.1.1/docs/error_codes.rst
--- old/pydocstyle-5.0.2/docs/error_codes.rst 2020-01-08 13:37:01.000000000
+0100
+++ new/pydocstyle-5.1.1/docs/error_codes.rst 2020-08-29 22:52:53.000000000
+0200
@@ -9,19 +9,23 @@
Default conventions
-------------------
-Not all error codes are checked for by default. There are three
-conventions that may be used by pydocstyle: ``pep257``, ``numpy`` and
``google``.
+Not all error codes are checked for by default. There are three conventions
+that may be used by pydocstyle: ``pep257``, ``numpy`` and ``google``.
-The pep257 convention, which is enabled by default in pydocstyle,
-checks for all of the above errors except for D203, D212, D213, D214,
-D215, D404, D405, D406, D407, D408, D409, D410, D411, D413, D415, D416 and D417
-(as specified in `PEP257 <http://www.python.org/dev/peps/pep-0257/>`_).
+The ``pep257`` convention (specified in `PEP257
+<http://www.python.org/dev/peps/pep-0257/>`_), which is enabled by default in
+pydocstyle, checks for all of the above errors except for D203, D212, D213,
+D214, D215, D404, D405, D406, D407, D408, D409, D410, D411, D413, D415, D416
+and D417.
-The numpy convention checks for all of the above errors except for
-D107, D203, D212, D213, D402, D413, D415, D416 and D417.
+The ``numpy`` convention added in v2.0.0 supports the `numpydoc docstring
+<https://github.com/numpy/numpydoc>`_ standard. This checks all of of the
+errors except for D107, D203, D212, D213, D402, D413, D415, D416, and D417.
-The google convention checks for all of the above errors except for
-D203, D204, D213, D215, D400, D401, D404, D406, D407, D408, D409 and D413.
+The ``google`` convention added in v4.0.0 supports the `Google Python Style
+Guide <https://google.github.io/styleguide/pyguide.html>`_. This checks for
+all the errors except D203, D204, D213, D215, D400, D401, D404, D406, D407,
+D408, D409 and D413.
These conventions may be specified using `--convention=<name>` when
running pydocstyle from the command line or by specifying the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/docs/release_notes.rst
new/pydocstyle-5.1.1/docs/release_notes.rst
--- old/pydocstyle-5.0.2/docs/release_notes.rst 2020-01-08 13:37:01.000000000
+0100
+++ new/pydocstyle-5.1.1/docs/release_notes.rst 2020-08-29 22:52:53.000000000
+0200
@@ -4,6 +4,35 @@
**pydocstyle** version numbers follow the
`Semantic Versioning <http://semver.org/>`_ specification.
+
+5.1.1 - August 29th, 2020
+---------------------------
+
+Bug Fixes
+
+* Fix ``IndexError`` crash on one-line backslashed docstrings (#506).
+
+
+5.1.0 - August 22nd, 2020
+---------------------------
+
+New Features
+
+* Skip function arguments prefixed with `_` in D417 check (#440).
+
+Bug Fixes
+
+* Update convention support documentation (#386, #393)
+* Detect inner asynchronous functions for D202 (#467)
+* Fix indentation error while parsing class methods (#441).
+* Fix a bug in parsing Google-style argument description.
+ The bug caused some argument names to go unreported in D417 (#448).
+* Fixed an issue where skipping errors on module level docstring via #noqa
+ failed when there where more prior comments (#446).
+* Support backslash-continued descriptions in docstrings (#472).
+* Correctly detect publicity of modules inside directories (#470, #494).
+
+
5.0.2 - January 8th, 2020
---------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/docs/snippets/publicity.rst
new/pydocstyle-5.1.1/docs/snippets/publicity.rst
--- old/pydocstyle-5.0.2/docs/snippets/publicity.rst 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/docs/snippets/publicity.rst 2020-08-29
22:52:53.000000000 +0200
@@ -10,7 +10,9 @@
considered *public* if -
1. Its immediate parent is public *and*
-2. Its name does not contain a single leading underscore.
+2. Its name does *not* start with a single or double underscore.
+
+ a. Note, names that start and end with a double underscore are *public*
(e.g. ``__init__.py``).
A construct's immediate parent is the construct that contains it. For example,
a method's parent is a class object. A class' parent is usually a module, but
@@ -25,6 +27,12 @@
also considered private since its parent is a private class, even though its
name does not begin with a single underscore.
+Note, a module's parent is recursively checked upward until we reach a
directory
+in ``sys.path`` to avoid considering the complete filepath of a module.
+For example, consider the module ``/_foo/bar/baz.py``.
+If ``PYTHONPATH`` is set to ``/``, then ``baz.py`` is *private*.
+If ``PYTHONPATH`` is set to ``/_foo/``, then ``baz.py`` is *public*.
+
Modules are parsed to look if ``__all__`` is defined. If so, only those top
level constructs are considered public. The parser looks for ``__all__``
defined as a literal list or tuple. As the parser doesn't execute the module,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/setup.py
new/pydocstyle-5.1.1/setup.py
--- old/pydocstyle-5.0.2/setup.py 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/setup.py 2020-08-29 22:52:53.000000000 +0200
@@ -2,7 +2,7 @@
import sys
# Do not update the version manually - it is managed by `bumpversion`.
-version = '5.0.2'
+version = '5.1.1'
requirements = [
@@ -42,4 +42,7 @@
'pydocstyle = pydocstyle.cli:main',
],
},
+ project_urls={
+ 'Release Notes':
'http://www.pydocstyle.org/en/latest/release_notes.html',
+ },
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/pydocstyle/checker.py
new/pydocstyle-5.1.1/src/pydocstyle/checker.py
--- old/pydocstyle-5.0.2/src/pydocstyle/checker.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/pydocstyle/checker.py 2020-08-29
22:52:53.000000000 +0200
@@ -96,9 +96,9 @@
r"(\w+)" # Followed by 1 or more unicode chars, numbers or
underscores
# The above is captured as the first group as this is
the paramater name.
r"\s*" # Followed by 0 or more whitespace characters
- r"\(?(.*?)\)?" # Matches patterns contained within round brackets.
- # The `(.*?)` is the second capturing group which
matches any sequence of
- # characters in a non-greedy way (denoted by the `*?`)
+ r"(\(.*?\))?" # Matches patterns contained within round brackets.
+ # The `.*?`matches any sequence of characters in a
non-greedy
+ # way (denoted by the `*?`)
r"\s*" # Followed by 0 or more whitespace chars
r":" # Followed by a colon
".+" # Followed by 1 or more characters - which is the
docstring for the parameter
@@ -203,7 +203,7 @@
# class.
if not (
blanks_after_count == 1 and
- re(r"\s+(?:(?:class|def)\s|@)").match(after)
+ re(r"\s+(?:(?:class|def|async def)\s|@)").match(after)
):
yield violations.D202(blanks_after_count)
@@ -278,14 +278,17 @@
indent = self._get_docstring_indent(definition, docstring)
lines = docstring.split('\n')
if len(lines) > 1:
- lines = lines[1:] # First line does not need indent.
+ # First line and line continuations need no indent.
+ lines = [line for i, line in enumerate(lines)
+ if i and not lines[i-1].endswith('\\')]
indents = [leading_space(l) for l in lines if not is_blank(l)]
if set(' \t') == set(''.join(indents) + indent):
yield violations.D206()
- if (len(indents) > 1 and min(indents[:-1]) > indent or
- indents[-1] > indent):
+ if (len(indents) > 1 and min(indents[:-1]) > indent) or (
+ len(indents) > 0 and indents[-1] > indent
+ ):
yield violations.D208()
- if min(indents) < indent:
+ if len(indents) > 0 and min(indents) < indent:
yield violations.D207()
@check_for(Definition)
@@ -703,7 +706,9 @@
"""
docstring_args = set()
section_level_indent = leading_space(context.line)
- content = context.following_lines
+ # Join line continuations, then resplit by line.
+ content = (
+ '\n'.join(context.following_lines).replace('\\\n', '').split('\n'))
for current_line, next_line in zip(content, content[1:]):
# All parameter definitions in the Numpy parameters
# section must be at the same indent level as the section
@@ -764,6 +769,13 @@
# positional argument as it is `cls` or `self`
if definition.kind == 'method' and not definition.is_static:
function_args = function_args[1:]
+ # Filtering out any arguments prefixed with `_` marking them
+ # as private.
+ function_args = [
+ arg_name
+ for arg_name in function_args
+ if not is_def_arg_private(arg_name)
+ ]
missing_args = set(function_args) - docstring_args
if missing_args:
yield violations.D417(", ".join(sorted(missing_args)),
@@ -996,10 +1008,24 @@
if result is not None:
return result.group()
+def is_def_arg_private(arg_name):
+ """Return a boolean indicating if the argument name is private."""
+ return arg_name.startswith("_")
-def get_function_args(function_string):
+def get_function_args(function_source):
"""Return the function arguments given the source-code string."""
- function_arg_node =
ast.parse(textwrap.dedent(function_string)).body[0].args
+ # We are stripping the whitespace from the left of the
+ # function source.
+ # This is so that if the docstring has incorrectly
+ # indented lines, which are at a lower indent than the
+ # function source, we still dedent the source correctly
+ # and the AST parser doesn't throw an error.
+ try:
+ function_arg_node = ast.parse(function_source.lstrip()).body[0].args
+ except SyntaxError:
+ # If we still get a syntax error, we don't want the
+ # the checker to crash. Instead we just return a blank list.
+ return []
arg_nodes = function_arg_node.args
kwonly_arg_nodes = function_arg_node.kwonlyargs
return [arg_node.arg for arg_node in chain(arg_nodes, kwonly_arg_nodes)]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/pydocstyle/cli.py
new/pydocstyle-5.1.1/src/pydocstyle/cli.py
--- old/pydocstyle-5.0.2/src/pydocstyle/cli.py 2020-01-08 13:37:01.000000000
+0100
+++ new/pydocstyle-5.1.1/src/pydocstyle/cli.py 2020-08-29 22:52:53.000000000
+0200
@@ -71,7 +71,7 @@
def setup_stream_handlers(conf):
- """Setup logging stream handlers according to the options."""
+ """Set up logging stream handlers according to the options."""
class StdoutFilter(logging.Filter):
def filter(self, record):
return record.levelno in (logging.DEBUG, logging.INFO)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/pydocstyle/config.py
new/pydocstyle-5.1.1/src/pydocstyle/config.py
--- old/pydocstyle-5.0.2/src/pydocstyle/config.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/pydocstyle/config.py 2020-08-29
22:52:53.000000000 +0200
@@ -463,7 +463,7 @@
'known errors: %s', part)
expanded_codes.update(codes_to_add)
except TypeError as e:
- raise IllegalConfiguration(e)
+ raise IllegalConfiguration(e) from e
return expanded_codes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/pydocstyle/parser.py
new/pydocstyle-5.1.1/src/pydocstyle/parser.py
--- old/pydocstyle-5.0.2/src/pydocstyle/parser.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/pydocstyle/parser.py 2020-08-29
22:52:53.000000000 +0200
@@ -1,10 +1,12 @@
"""Python code parser."""
+import sys
import textwrap
import tokenize as tk
from itertools import chain, dropwhile
from re import compile as re
from io import StringIO
+from pathlib import Path
from .utils import log
@@ -14,6 +16,8 @@
class ParseError(Exception):
+ """An error parsing contents of a Python file."""
+
def __str__(self):
return "Cannot parse file."
@@ -111,7 +115,40 @@
@property
def is_public(self):
- return not self.name.startswith('_') or self.name.startswith('__')
+ """Return True iff the module is considered public.
+
+ This helps determine if it requires a docstring.
+ """
+ module_name = Path(self.name).stem
+ return (
+ not self._is_inside_private_package() and
+ self._is_public_name(module_name)
+ )
+
+ def _is_inside_private_package(self):
+ """Return True if the module is inside a private package."""
+ path = Path(self.name).parent # Ignore the actual module's name.
+ syspath = [Path(p) for p in sys.path] # Convert to pathlib.Path.
+
+ # Bail if we are at the root directory or in `PYTHONPATH`.
+ while path != path.parent and path not in syspath:
+ if self._is_private_name(path.name):
+ return True
+ path = path.parent
+
+ return False
+
+ def _is_public_name(self, module_name):
+ """Determine whether a "module name" (i.e. module or package name) is
public."""
+ return (
+ not module_name.startswith('_') or (
+ module_name.startswith('__') and module_name.endswith('__')
+ )
+ )
+
+ def _is_private_name(self, module_name):
+ """Determine whether a "module name" (i.e. module or package name) is
private."""
+ return not self._is_public_name(module_name)
def __str__(self):
return 'at module level'
@@ -183,6 +220,7 @@
@property
def is_static(self):
+ """Return True iff the method is static."""
for decorator in self.decorators:
if decorator.name == "staticmethod":
return True
@@ -221,6 +259,7 @@
the start and end of the token.
"""
+
def __new__(cls, v, start, end):
return str.__new__(cls, v)
@@ -372,9 +411,9 @@
return None
def parse_decorators(self):
- """Called after first @ is found.
+ """Parse decorators into self._accumulated_decorators.
- Parse decorators into self._accumulated_decorators.
+ Called after first @ is found.
Continue to do so until encountering the 'def' or 'class' start token.
"""
name = []
@@ -576,12 +615,20 @@
def parse_skip_comment(self):
"""Parse a definition comment for noqa skips."""
skipped_error_codes = ''
- if self.current.kind == tk.COMMENT:
- if 'noqa: ' in self.current.value:
- skipped_error_codes = ''.join(
- self.current.value.split('noqa: ')[1:])
- elif self.current.value.startswith('# noqa'):
- skipped_error_codes = 'all'
+ while self.current.kind in (tk.COMMENT, tk.NEWLINE, tk.NL):
+ if self.current.kind == tk.COMMENT:
+ if 'noqa: ' in self.current.value:
+ skipped_error_codes = ''.join(
+ self.current.value.split('noqa: ')[1:])
+ elif self.current.value.startswith('# noqa'):
+ skipped_error_codes = 'all'
+ self.stream.move()
+ self.log.debug("parsing comments before docstring, token is %r
(%s)",
+ self.current.kind, self.current.value)
+
+ if skipped_error_codes:
+ break
+
return skipped_error_codes
def check_current(self, kind=None, value=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/pydocstyle/utils.py
new/pydocstyle-5.1.1/src/pydocstyle/utils.py
--- old/pydocstyle-5.0.2/src/pydocstyle/utils.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/pydocstyle/utils.py 2020-08-29
22:52:53.000000000 +0200
@@ -7,7 +7,7 @@
# Do not update the version manually - it is managed by `bumpversion`.
-__version__ = '5.0.2'
+__version__ = '5.1.1'
log = logging.getLogger(__name__)
#: Regular expression for stripping non-alphanumeric characters
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/pydocstyle/wordlists.py
new/pydocstyle-5.1.1/src/pydocstyle/wordlists.py
--- old/pydocstyle-5.0.2/src/pydocstyle/wordlists.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/pydocstyle/wordlists.py 2020-08-29
22:52:53.000000000 +0200
@@ -35,8 +35,8 @@
yield line
-#: A dict mapping stemmed verbs to the imperative form
def make_imperative_verbs_dict(wordlist: Iterator[str]) -> Dict[str, Set[str]]:
+ """Create a dictionary mapping stemmed verbs to the imperative form."""
imperative_verbs = {} # type: Dict[str, Set[str]]
for word in wordlist:
imperative_verbs.setdefault(stem(word), set()).add(word)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/tests/parser_test.py
new/pydocstyle-5.1.1/src/tests/parser_test.py
--- old/pydocstyle-5.0.2/src/tests/parser_test.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/tests/parser_test.py 2020-08-29
22:52:53.000000000 +0200
@@ -4,6 +4,7 @@
import sys
import pytest
import textwrap
+from pathlib import Path
from pydocstyle.parser import Parser, ParseError
@@ -562,19 +563,75 @@
assert inner_function.decorators[0].name == 'a'
-def test_module_publicity():
- """Test that a module that has a single leading underscore is private."""
[email protected]("public_path", (
+ Path(""),
+ Path("module.py"),
+ Path("package") / "module.py",
+ Path("package") / "__init__.py",
+ Path("") / "package" / "module.py",
+ Path("") / "__dunder__" / "package" / "module.py"
+))
+def test_module_publicity_with_public_path(public_path):
+ """Test module publicity with public path.
+
+ Module names such as my_module.py are considered public.
+
+ Special "dunder" modules,
+ with leading and trailing double-underscores (e.g. __init__.py) are public.
+
+ The same rules for publicity apply to both packages and modules.
+ """
parser = Parser()
code = CodeSnippet("")
-
- module = parser.parse(code, "filepath")
+ module = parser.parse(code, str(public_path))
assert module.is_public
- module = parser.parse(code, "_filepath")
+
[email protected]("private_path", (
+ # single underscore
+ Path("_private_module.py"),
+ Path("_private_package") / "module.py",
+ Path("_private_package") / "package" / "module.py",
+ Path("") / "_private_package" / "package" / "module.py",
+
+ # double underscore
+ Path("__private_module.py"),
+ Path("__private_package") / "module.py",
+ Path("__private_package") / "package" / "module.py",
+ Path("") / "__private_package" / "package" / "module.py"
+))
+def test_module_publicity_with_private_paths(private_path):
+ """Test module publicity with private path.
+
+ Module names starting with single or double-underscore are private.
+ For example, _my_private_module.py and __my_private_module.py.
+
+ Any module within a private package is considered private.
+
+ The same rules for publicity apply to both packages and modules.
+ """
+ parser = Parser()
+ code = CodeSnippet("")
+ module = parser.parse(code, str(private_path))
assert not module.is_public
- module = parser.parse(code, "__filepath")
- assert module.is_public
+
[email protected]("syspath,is_public", (
+ ("/", False),
+ ("_foo/", True),
+))
+def test_module_publicity_with_different_sys_path(syspath,
+ is_public,
+ monkeypatch):
+ """Test module publicity for same path and different sys.path."""
+ parser = Parser()
+ code = CodeSnippet("")
+
+ monkeypatch.syspath_prepend(syspath)
+
+ path = Path("_foo") / "bar" / "baz.py"
+ module = parser.parse(code, str(path))
+ assert module.is_public == is_public
def test_complex_module():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/tests/test_cases/expected.py
new/pydocstyle-5.1.1/src/tests/test_cases/expected.py
--- old/pydocstyle-5.0.2/src/tests/test_cases/expected.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/tests/test_cases/expected.py 2020-08-29
22:52:53.000000000 +0200
@@ -4,13 +4,13 @@
def __init__(self):
self.expected = set()
- def expect(self, *args, arg_count=0):
+ def expect(self, *args, arg_count=0, func_name=""):
"""Decorator that expects a certain PEP 257 violation."""
# The `arg_count` parameter helps the decorator
# with functions that have positional arguments.
if len(args) == 1:
def decorate(f):
- self.expected.add((f.__name__, args[0]))
+ self.expected.add((func_name or f.__name__, args[0]))
f(*[None]*arg_count)
return f
return decorate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/tests/test_cases/functions.py
new/pydocstyle-5.1.1/src/tests/test_cases/functions.py
--- old/pydocstyle-5.0.2/src/tests/test_cases/functions.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/tests/test_cases/functions.py 2020-08-29
22:52:53.000000000 +0200
@@ -29,6 +29,15 @@
pass
+def func_with_inner_async_func_after():
+ """Test a function with inner async function after docstring."""
+
+ async def inner():
+ pass
+
+ pass
+
+
def fake_decorator(decorated):
"""Fake decorator used to test decorated inner func."""
return decorated
@@ -44,6 +53,16 @@
pass
+def func_with_inner_decorated_async_func_after():
+ """Test a function with inner decorated async function after docstring."""
+
+ @fake_decorator
+ async def inner():
+ pass
+
+ pass
+
+
def func_with_inner_class_after():
"""Test a function with inner class after docstring."""
@@ -51,3 +70,8 @@
pass
pass
+
+
+def func_with_weird_backslash():
+ """Test a function with a weird backslash.\
+"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/tests/test_cases/noqa.py
new/pydocstyle-5.1.1/src/tests/test_cases/noqa.py
--- old/pydocstyle-5.0.2/src/tests/test_cases/noqa.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/tests/test_cases/noqa.py 2020-08-29
22:52:53.000000000 +0200
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# noqa: D400,D415
"""Test case for "# noqa" comments"""
from .expected import Expectation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/tests/test_cases/sections.py
new/pydocstyle-5.1.1/src/tests/test_cases/sections.py
--- old/pydocstyle-5.0.2/src/tests/test_cases/sections.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/tests/test_cases/sections.py 2020-08-29
22:52:53.000000000 +0200
@@ -274,11 +274,30 @@
"""
+@expect("D417: Missing argument descriptions in the docstring "
+ "(argument(s) y are missing descriptions in "
+ "'bar' docstring)", func_name="bar")
+def _test_nested_functions():
+ x = 1
+
+ def bar(y=2): # noqa: D207, D213, D406, D407
+ """Nested function test for docstrings.
+
+ Will this work when referencing x?
+
+ Args:
+ x: Test something
+that is broken.
+
+ """
+ print(x)
+
+
@expect(_D213)
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) y are missing descriptions in "
"'test_missing_google_args' docstring)")
-def test_missing_google_args(x=1, y=2): # noqa: D406, D407
+def test_missing_google_args(x=1, y=2, _private=3): # noqa: D406, D407
"""Toggle the gizmo.
Args:
@@ -290,7 +309,7 @@
class TestGoogle: # noqa: D203
"""Test class."""
- def test_method(self, test, another_test): # noqa: D213, D407
+ def test_method(self, test, another_test, _): # noqa: D213, D407
"""Test a valid args section.
Args:
@@ -301,8 +320,8 @@
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) test, y, z are missing descriptions in "
- "'test_missing_args' docstring)", arg_count=4)
- def test_missing_args(self, test, x, y, z=3): # noqa: D213, D407
+ "'test_missing_args' docstring)", arg_count=5)
+ def test_missing_args(self, test, x, y, z=3, _private_arg=3): # noqa:
D213, D407
"""Test a valid args section.
Args:
@@ -313,8 +332,8 @@
@classmethod
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) test, y, z are missing descriptions in "
- "'test_missing_args_class_method' docstring)", arg_count=4)
- def test_missing_args_class_method(cls, test, x, y, z=3): # noqa: D213,
D407
+ "'test_missing_args_class_method' docstring)", arg_count=5)
+ def test_missing_args_class_method(cls, test, x, y, _, z=3): # noqa:
D213, D407
"""Test a valid args section.
Args:
@@ -326,8 +345,8 @@
@staticmethod
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) a, y, z are missing descriptions in "
- "'test_missing_args_static_method' docstring)", arg_count=3)
- def test_missing_args_static_method(a, x, y, z=3): # noqa: D213, D407
+ "'test_missing_args_static_method' docstring)", arg_count=4)
+ def test_missing_args_static_method(a, x, y, _test, z=3): # noqa: D213,
D407
"""Test a valid args section.
Args:
@@ -335,18 +354,49 @@
"""
+ @staticmethod
+ @expect("D417: Missing argument descriptions in the docstring "
+ "(argument(s) a, b are missing descriptions in "
+ "'test_missing_docstring' docstring)", arg_count=2)
+ def test_missing_docstring(a, b): # noqa: D213, D407
+ """Test a valid args section.
+
+ Args:
+ a:
+
+ """
+
+ @staticmethod
+ @expect("D417: Missing argument descriptions in the docstring "
+ "(argument(s) skip, verbose are missing descriptions in "
+ "'test_missing_docstring_another' docstring)", arg_count=2)
+ def test_missing_docstring_another(skip, verbose): # noqa: D213, D407
+ """Do stuff.
+
+ Args:
+ skip (:attr:`.Skip`):
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ Etiam at tellus a tellus faucibus maximus. Curabitur tellus
+ mauris, semper id vehicula ac, feugiat ut tortor.
+ verbose (bool):
+ If True, print out as much infromation as possible.
+ If False, print out concise "one-liner" information.
+
+ """
+
@expect(_D213)
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) y are missing descriptions in "
"'test_missing_numpy_args' docstring)")
-def test_missing_numpy_args(x=1, y=2): # noqa: D406, D407
+def test_missing_numpy_args(_private_arg=0, x=1, y=2): # noqa: D406, D407
"""Toggle the gizmo.
Parameters
----------
x : int
- The greatest integer.
+ The greatest integer in the history \
+of the entire world.
"""
@@ -354,13 +404,19 @@
class TestNumpy: # noqa: D203
"""Test class."""
- def test_method(self, test, another_test, x=1, y=2): # noqa: D213, D407
+ def test_method(self, test, another_test, z, _, x=1, y=2, _private_arg=1):
# noqa: D213, D407
"""Test a valid args section.
+ Some long string with a \
+line continuation.
+
Parameters
----------
test, another_test
Some parameters without type.
+ z : some parameter with a very long type description that requires a \
+line continuation.
+ But no further description.
x, y : int
Some integer parameters.
@@ -368,8 +424,8 @@
@expect("D417: Missing argument descriptions in the docstring "
"(argument(s) test, y, z are missing descriptions in "
- "'test_missing_args' docstring)", arg_count=4)
- def test_missing_args(self, test, x, y, z=3, t=1): # noqa: D213, D407
+ "'test_missing_args' docstring)", arg_count=5)
+ def test_missing_args(self, test, x, y, z=3, t=1, _private=0): # noqa:
D213, D407
"""Test a valid args section.
Parameters
@@ -425,3 +481,20 @@
Zoneeeeee!
"""
+
+
+class TestIncorrectIndent: # noqa: D203
+ """Test class."""
+
+ @expect("D417: Missing argument descriptions in the docstring "
+ "(argument(s) y are missing descriptions in "
+ "'test_incorrect_indent' docstring)", arg_count=3)
+ def test_incorrect_indent(self, x=1, y=2): # noqa: D207, D213, D407
+ """Reproducing issue #437.
+
+Testing this incorrectly indented docstring.
+
+ Args:
+ x: Test argument.
+
+ """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/src/tests/test_integration.py
new/pydocstyle-5.1.1/src/tests/test_integration.py
--- old/pydocstyle-5.0.2/src/tests/test_integration.py 2020-01-08
13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/src/tests/test_integration.py 2020-08-29
22:52:53.000000000 +0200
@@ -150,10 +150,9 @@
def test_pep257_conformance():
"""Test that we conform to PEP 257."""
base_dir = (pathlib.Path(__file__).parent / '..').resolve()
- src_dirs = (base_dir, base_dir / 'tests')
- src_files = []
- for src_dir in src_dirs:
- src_files.extend(str(path) for path in src_dir.glob('*.py'))
+ excluded = base_dir / 'tests' / 'test_cases'
+ src_files = (str(path) for path in base_dir.glob('**/*.py')
+ if excluded not in path.parents)
ignored = {'D104', 'D105'}
select = violations.conventions.pep257 - ignored
@@ -1124,3 +1123,70 @@
out, err, code = env.invoke(args="-v")
assert code == 0
assert "IndentationError: unexpected indent" not in err
+
+
+def test_only_comment_file(env):
+ """Test that file with only comments does only cause D100."""
+ with env.open('comments.py', 'wt') as comments:
+ comments.write(
+ '#!/usr/bin/env python3\n'
+ '# -*- coding: utf-8 -*-\n'
+ '# Useless comment\n'
+ '# Just another useless comment\n'
+ )
+
+ out, _, code = env.invoke()
+ assert 'D100' in out
+ out = out.replace('D100', '')
+ for err in {'D1', 'D2', 'D3', 'D4'}:
+ assert err not in out
+ assert code == 1
+
+
+def test_comment_plus_docstring_file(env):
+ """Test that file with comments and docstring does not cause errors."""
+ with env.open('comments_plus.py', 'wt') as comments_plus:
+ comments_plus.write(
+ '#!/usr/bin/env python3\n'
+ '# -*- coding: utf-8 -*-\n'
+ '# Useless comment\n'
+ '# Just another useless comment\n'
+ '"""Module docstring."""\n'
+ )
+
+ out, _, code = env.invoke()
+ assert '' == out
+ assert code == 0
+
+
+def test_only_comment_with_noqa_file(env):
+ """Test that file with noqa and only comments does not cause errors."""
+ with env.open('comments.py', 'wt') as comments:
+ comments.write(
+ '#!/usr/bin/env python3\n'
+ '# -*- coding: utf-8 -*-\n'
+ '# Useless comment\n'
+ '# Just another useless comment\n'
+ '# noqa: D100\n'
+ )
+
+ out, _, code = env.invoke()
+ assert 'D100' not in out
+ assert code == 0
+
+
+def test_comment_with_noqa_plus_docstring_file(env):
+ """Test that file with comments, noqa, docstring does not cause errors."""
+ with env.open('comments_plus.py', 'wt') as comments_plus:
+ comments_plus.write(
+ '#!/usr/bin/env python3\n'
+ '# -*- coding: utf-8 -*-\n'
+ '# Useless comment\n'
+ '# Just another useless comment\n'
+ '# noqa: D400\n'
+ '"""Module docstring without period"""\n'
+ )
+
+ out, _, code = env.invoke()
+ assert '' == out
+ assert code == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pydocstyle-5.0.2/tox.ini new/pydocstyle-5.1.1/tox.ini
--- old/pydocstyle-5.0.2/tox.ini 2020-01-08 13:37:01.000000000 +0100
+++ new/pydocstyle-5.1.1/tox.ini 2020-08-29 22:52:53.000000000 +0200
@@ -4,7 +4,7 @@
# install tox" and then run "tox" from this directory.
[tox]
-envlist = {py35,py36,py37,py38}-{tests,install},py36-docs
+envlist = {py35,py36,py37,py38}-{tests,install},docs,install,py36-docs
[testenv]
download = true
@@ -20,34 +20,43 @@
-rrequirements/runtime.txt
-rrequirements/tests.txt
-[testenv:py37-install]
+[testenv:install]
skip_install = True
commands =
python setup.py bdist_wheel
pip install --no-index --find-links=dist pydocstyle
pydocstyle --help
+[testenv:docs]
+changedir = docs
+deps =
+ -rrequirements/runtime.txt
+ -rrequirements/docs.txt
+commands = sphinx-build -b html . _build
+
+[testenv:py36-docs]
+changedir = {[testenv:docs]changedir}
+deps = {[testenv:docs]deps}
+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:py37-install]skip_install}
-commands = {[testenv:py37-install]commands}
+skip_install = {[testenv:install]skip_install}
+commands = {[testenv:install]commands}
[testenv:py36-install]
-skip_install = {[testenv:py37-install]skip_install}
-commands = {[testenv:py37-install]commands}
+skip_install = {[testenv:install]skip_install}
+commands = {[testenv:install]commands}
-[testenv:py38-install]
-skip_install = {[testenv:py37-install]skip_install}
-commands = {[testenv:py37-install]commands}
+[testenv:py37-install]
+skip_install = {[testenv:install]skip_install}
+commands = {[testenv:install]commands}
-[testenv:py36-docs]
-changedir=docs
-deps =
- -rrequirements/runtime.txt
- -rrequirements/docs.txt
-commands=sphinx-build -b html . _build
+[testenv:py38-install]
+skip_install = {[testenv:install]skip_install}
+commands = {[testenv:install]commands}
[pytest]
pep8ignore =