Skip to content
Snippets Groups Projects
Commit ac20e2c3 authored by Daniel Pope's avatar Daniel Pope Committed by Amir Rachum
Browse files

Report docstring content violations on docstring line (#238)

* Report docstring content violations on docstring start line (fixes #83)

* Add description of line number change to release notes

* Change title of development version in release notes

* Add issue and PR numbers to release notes
parent df872e43
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -4,6 +4,14 @@ Release Notes
**pydocstyle** version numbers follow the
`Semantic Versioning <http://semver.org/>`_ specification.
 
Current development version
---------------------------
New features
* Violations are now reported on the line where the docstring starts, not the
line of the ``def``/``class`` it corresponds to (#238, #83).
 
2.1.1 - October 9th, 2017
-------------------------
Loading
Loading
Loading
Loading
@@ -80,6 +80,13 @@ class Definition(Value):
def __iter__(self):
return chain([self], *self.children)
 
@property
def error_lineno(self):
"""Get the line number with which to report violations."""
if isinstance(self.docstring, Docstring):
return self.docstring.start
return self.start
@property
def _publicity(self):
return {True: 'public', False: 'private'}[self.is_public]
Loading
Loading
@@ -210,6 +217,21 @@ class Decorator(Value):
_fields = 'name arguments'.split()
 
 
class Docstring(str):
"""Represent a docstring.
This is a string, but has additional start/end attributes representing
the start and end of the token.
"""
def __new__(cls, v, start, end):
return str.__new__(cls, v)
def __init__(self, v, start, end):
self.start = start
self.end = end
VARIADIC_MAGIC_METHODS = ('__init__', '__call__', '__new__')
 
 
Loading
Loading
@@ -334,7 +356,11 @@ class Parser(object):
self.log.debug("parsing docstring, token is %r (%s)",
self.current.kind, self.current.value)
if self.current.kind == tk.STRING:
docstring = self.current.value
docstring = Docstring(
self.current.value,
self.current.start[0],
self.current.end[0]
)
self.stream.move()
return docstring
return None
Loading
Loading
Loading
Loading
@@ -38,7 +38,7 @@ class Error(object):
self.explanation = explanation
 
filename = property(lambda self: self.definition.module.name)
line = property(lambda self: self.definition.start)
line = property(lambda self: self.definition.error_lineno)
 
@property
def message(self):
Loading
Loading
Loading
Loading
@@ -36,10 +36,13 @@ def test_function():
assert function.decorators == []
assert function.children == []
assert function.docstring == '"""Do something."""'
assert function.docstring.start == 2
assert function.docstring.end == 2
assert function.kind == 'function'
assert function.parent == module
assert function.start == 1
assert function.end == 3
assert function.error_lineno == 2
assert function.source == code.getvalue()
assert function.is_public
assert str(function) == 'in public function `do_something`'
Loading
Loading
@@ -95,6 +98,7 @@ def test_nested_function():
assert outer_function.parent == module
assert outer_function.start == 1
assert outer_function.end == 6
assert outer_function.error_lineno == 2
assert outer_function.source == code.getvalue()
assert outer_function.is_public
assert str(outer_function) == 'in public function `outer_function`'
Loading
Loading
@@ -107,6 +111,7 @@ def test_nested_function():
assert inner_function.parent == outer_function
assert inner_function.start == 3
assert inner_function.end == 5
assert inner_function.error_lineno == 4
assert textwrap.dedent(inner_function.source) == textwrap.dedent("""\
def inner_function():
'''This is the inner function.'''
Loading
Loading
@@ -239,6 +244,7 @@ def test_class():
assert klass.parent == module
assert klass.start == 1
assert klass.end == 3
assert klass.error_lineno == 3
assert klass.source == code.getvalue()
assert klass.is_public
assert str(klass) == 'in public class `TestedClass`'
Loading
Loading
@@ -264,6 +270,7 @@ def test_public_method():
assert klass.parent == module
assert klass.start == 1
assert klass.end == 5
assert klass.error_lineno == 1
assert klass.source == code.getvalue()
assert klass.is_public
assert str(klass) == 'in public class `TestedClass`'
Loading
Loading
@@ -276,6 +283,7 @@ def test_public_method():
assert method.parent == klass
assert method.start == 2
assert method.end == 5
assert method.error_lineno == 3
assert textwrap.dedent(method.source) == textwrap.dedent("""\
def do_it(param):
\"""Do the 'it'\"""
Loading
Loading
@@ -307,6 +315,7 @@ def test_private_method():
assert klass.parent == module
assert klass.start == 1
assert klass.end == 5
assert klass.error_lineno == 1
assert klass.source == code.getvalue()
assert klass.is_public
assert str(klass) == 'in public class `TestedClass`'
Loading
Loading
@@ -319,6 +328,7 @@ def test_private_method():
assert method.parent == klass
assert method.start == 2
assert method.end == 5
assert method.error_lineno == 3
assert textwrap.dedent(method.source) == textwrap.dedent("""\
def _do_it(param):
\"""Do the 'it'\"""
Loading
Loading
@@ -348,6 +358,7 @@ def test_magic_method():
assert klass.parent == module
assert klass.start == 1
assert klass.end == 3
assert klass.error_lineno == 1
assert klass.source == code.getvalue()
assert klass.is_public
assert str(klass) == 'in public class `TestedClass`'
Loading
Loading
@@ -360,6 +371,7 @@ def test_magic_method():
assert method.parent == klass
assert method.start == 2
assert method.end == 3
assert method.error_lineno == 2
assert textwrap.dedent(method.source) == textwrap.dedent("""\
def __str__(self):
return "me"
Loading
Loading
@@ -388,6 +400,7 @@ def test_nested_class():
assert outer_class.parent == module
assert outer_class.start == 1
assert outer_class.end == 4
assert outer_class.error_lineno == 2
assert outer_class.source == code.getvalue()
assert outer_class.is_public
assert str(outer_class) == 'in public class `OuterClass`'
Loading
Loading
@@ -401,6 +414,7 @@ def test_nested_class():
assert inner_class.parent == outer_class
assert inner_class.start == 3
assert inner_class.end == 4
assert inner_class.error_lineno == 4
assert textwrap.dedent(inner_class.source) == textwrap.dedent("""\
class InnerClass(object):
"An inner docstring."
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment