pycqa / pydocstyle Goto Github PK
View Code? Open in Web Editor NEWdocstring style checker
Home Page: http://pydocstyle.org
License: MIT License
docstring style checker
Home Page: http://pydocstyle.org
License: MIT License
Errors are printed with the print statement, and by default this goes to stdout.
The --match_dir
is not respected properly when multiple directories exist:
> mkdir bar
> mkdir bat
> mkdir baz
> touch bar/bar.py
> touch bat/bat.py
> touch baz/baz.py
> pep257 --match-dir=bar
./bar/bar.py:1 at module level:
D100: Docstring missing
./baz/baz.py:1 at module level:
D100: Docstring missing
bar
is correctly matched, and bat
is correctly excluded, but baz
is incorrectly included.
I have a candidate fix for this - will submit pull request.
Missing docstring in __init__.py
files should be a different error than in a regular module.
This is a highly useful package! I am currently working on a project where I would like to add pep8 and pep257 conformance into my automated tests. To do this, it would be great if this project was published on PyPi so I simply could add it as a test dependency.
pep8 is already published on PyPi. How about publishing this, too? Have you thought about it? Are there any showstoppers? I'd love to contribute a setup.py
file if that's all it takes.
Running the script on the following code:
""" Description of the module. """
class TestClass(object):
""" Description of the class
"""
def __init__(self):
pass
Gives the following output:
$ pep257.test.py
================================================================================
Note: checks are relaxed for scripts (with #!) compared to modules.
test.py:5:4: First line should end with a period.
test.py:5:4: First line should end with a period.
test.py:5:4: One-liner docstrings should fit on one line with quotes.
test.py:5:4: One-liner docstrings should fit on one line with quotes.
While we run pep257.check_files(files). ( API)
It is right to detect indentation problem. But then it should not be stopping the execution. How about we handle this exception and report it in the output ? or its intentionally left like that ?
Or am i missing some config ?
File "/Users/anupkalburgi/active/active/lib/python2.7/site-packages/pep257.py", line 197, in parse_top_level
kind, value, (line, char), _, _ = next(token_gen)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/tokenize.py", line 351, in generate_tokens
("", lnum, pos, line))
File "", line 9
except:
https://pypi.python.org/pypi/pep257 looks like this:
Typically this happens when PyPI encounters a ReStructuredText syntax error or a feature that is explicitly disabled for PyPI (like non-absolute URLs in links).
Usually I use restview's --pypi-strict
mode to discover the source of the error, but here restview doesn't complain, so I"m baffled.
Steps to reproduce
pep257
on this fileTraceback (most recent call last):
File "/usr/bin/pep257", line 8, in <module>
sys.exit(main(*parse_options()))
File "/usr/lib/python2.7/site-packages/pep257.py", line 411, in main
for error in check(collected, ignore=options.ignore.split(',')):
File "/usr/lib/python2.7/site-packages/pep257.py", line 394, in check
for error in PEP257Checker().check_source(source, filename):
File "/usr/lib/python2.7/site-packages/pep257.py", line 440, in check_source
module = parse(StringIO(source), filename)
File "/usr/lib/python2.7/site-packages/pep257.py", line 181, in __call__
return self.parse_module()
File "/usr/lib/python2.7/site-packages/pep257.py", line 252, in parse_module
children = list(self.parse_definitions(Module, all=True))
File "/usr/lib/python2.7/site-packages/pep257.py", line 212, in parse_definitions
for definition in self.parse_definitions(class_):
File "/usr/lib/python2.7/site-packages/pep257.py", line 209, in parse_definitions
yield self.parse_definition(class_._nest(token.value))
File "/usr/lib/python2.7/site-packages/pep257.py", line 268, in parse_definition
children = list(self.parse_definitions(class_))
File "/usr/lib/python2.7/site-packages/pep257.py", line 209, in parse_definitions
yield self.parse_definition(class_._nest(token.value))
File "/usr/lib/python2.7/site-packages/pep257.py", line 269, in parse_definition
assert self.current.kind == tk.DEDENT
AttributeError: 'NoneType' object has no attribute 'kind'
Running the script on the following code:
""" Description of the module
Another line in the description."""
class TestClass(object):
""" Description of the class
"""
def __init__(self):
pass
Should report errors on the module docstring:
But these errors are not reported.
According to PEP 257, for multi-line docstrings, "the summary line may be on the same line as the opening quotes or on the next line".
However, the current implementation of pep257 requires that the summary line be on the same line as the opening quotes. For instance, the following tests with the summary line on the second line fail even though they appear valid by PEP 257 and are quite common docstring formats:
check_ends_with_period:
check = pep257.check_ends_with_period
s4 = '''"""
Should end with a period.
"""'''
assert not check(s4, None, None)
check_blank_after_summary:
pep257.check_blank_after_summary
s4 = '''"""
Blank line missing after one-line summary.
"""'''
assert not check(s4, None, None)
Hi,
I was just working away and noticed that pep257 complains about init.py files:
goat/util/init.py:1:0: All modules should have docstrings.
Would it be ok to ignore these if they are empty/maybe all the time?
Marc
Hello,
I want to use your distribution in flake8. For this i need, please, entry point.
Thanks a lot
PEP 257 does not explicitly mention how to handle __all__
. The only thing it sais is:
all functions and classes exported by a module should have docstrings
I think __all__
is our best chance to decide which definitions are exported or not, as mentioned in #22.
Right now the this is handled by check_def_has_docstring
:
if is_script:
return # assume nothing is exported
def_name = context.split()[1]
if def_name.startswith('_') and not def_name.endswith('__'):
return # private, not exported
if not def_docstring:
return 0, len(context.split('\n')[0])
if not eval(def_docstring).strip():
return True
I suppose that instead of if is_script
we should check if def_name in __all__
. But the problem is how to access __all__
without evaluating each file?
in basic case __all__
is a one-liner which looks like:
__all__ = ['foo', 'bar', 'baz']
we could just search for it and evaluate that line. I guess that would make sense for a first implementation.
But then, what if __all__
spans multiple lines?
__all__ = ['foo', 'bar', 'baz',
'eggs', 'span']
or uses the split
trick?
__all__ = '''foo bar baz
eggs span'''.split()
or is populated dynamically?
__all__ = []
def public(f):
__all__.append(f.__name__)
return f
@public
def foo():
pass
@public
def bar():
pass
I guess we can't solve it in general case without executing the code. And we can't execute the code (maybe it writes to a file, or has some other side-effect). But we could decide on a way to retrieve __all__
for some cases.
What do you think?
With the following test file:
__all__ = (
'a',
'b',
'c',
)
def a():
pass
def b():
pass
def c():
pass
pep257 version 0.3.2 reports that it is unable to evaluate all:
Could not evaluate contents of __all__. That means pep257 cannot decide which definitions are public. Variable __all__ should be present at most once in each file, in form `__all__ = ('a_public_function', 'APublicClass', ...)`. More info on __all__: http://stackoverflow.com/q/44834/.
If I reformat all to include something on the opening line, pep257 is able to continue:
__all__ = ('a',
'b',
'c',
)
Running pep257.py on the following module:
""" Test """
class MyException(Exception):
""" My exception class. """
I get this error:
test.py:6:4: PEP257 Class docstring should have 1 blank line around them
The error is not shown if the code is changed to:
""" Test """
class MyException(Exception):
""" Description of the error. """
pass
Is this the expected behaviour? AFAIK the initial version is valid python code. It passes pep8 and pylint.
The version tagged 0.2.0 has a couple of PEP-8 warnings.
pep257.py:93:5: E301 expected 1 blank line, found 0
def any(iterable):
^
Separate top-level function and class definitions with two blank lines.
Method definitions inside a class are separated by a single blank line.
Extra blank lines may be used (sparingly) to separate groups of related
functions. Blank lines may be omitted between a bunch of related
one-liners (e.g. a set of dummy implementations).
Use blank lines in functions, sparingly, to indicate logical sections.
Okay: def a():\n pass\n\n\ndef b():\n pass
Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
E301: class Foo:\n b = 0\n def bar():\n pass
E302: def a():\n pass\n\ndef b(n):\n pass
E303: def a():\n pass\n\n\n\ndef b(n):\n pass
E303: def a():\n\n\n\n pass
E304: @decorator\n\ndef a():\n pass
And
pep257.py:119:5: E301 expected 1 blank line, found 0
def cached_func(*args, **kwargs):
^
Separate top-level function and class definitions with two blank lines.
Method definitions inside a class are separated by a single blank line.
Extra blank lines may be used (sparingly) to separate groups of related
functions. Blank lines may be omitted between a bunch of related
one-liners (e.g. a set of dummy implementations).
Use blank lines in functions, sparingly, to indicate logical sections.
Okay: def a():\n pass\n\n\ndef b():\n pass
Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
E301: class Foo:\n b = 0\n def bar():\n pass
E302: def a():\n pass\n\ndef b(n):\n pass
E303: def a():\n pass\n\n\n\ndef b(n):\n pass
E303: def a():\n\n\n\n pass
E304: @decorator\n\ndef a():\n pass```
not sure if this is the right place to report it, but there are no files to download at
https://pypi.python.org/pypi/pep257/0.4.1
whereas older versions are available.
Arun
Theses line (see below) are always output. It would be better if these could be either suppressed (with -q / --quiet) or only enabled with a verbose mode (-v / --verbose)
================================================================================
Note: checks are relaxed for scripts (with #!) compared to modules
pip install git+https://github.com/GreenSteam/pep257.git@8b331a850a45c57c43a762ff8133bcdea0bb3956#egg=pep257 09:21:05
Collecting git+https://github.com/GreenSteam/pep257.git@8b331a850a45c57c43a762ff8133bcdea0bb3956
Cloning https://github.com/GreenSteam/pep257.git (to 8b331a850a45c57c43a762ff8133bcdea0bb3956) to /var/folders/2w/kffqc_pj6m38rgrxlhk8z6nr0000gn/T/pip-gRke1t-build
Could not find a tag or branch '8b331a850a45c57c43a762ff8133bcdea0bb3956', assuming commit.
Installing collected packages: pep257
Running setup.py install for pep257
changing mode of build/scripts-2.7/pep257 from 644 to 755
changing mode of /Users/lvh/.pyenv/versions/otter/bin/pep257 to 755
Successfully installed pep257-0.4.0
~/C/r/otter: pep257 09:21:10
Traceback (most recent call last):
File "/Users/lvh/.pyenv/versions/otter/bin/pep257", line 3, in <module>
from pep257 import main, parse_options
ImportError: cannot import name parse_options
#75 might fix this accidentally (by replacing the current option parser). Cc @Nurdok?
To quote @sigmavirus24 from #58:
This is a better opportunity to start using readthedocs.org and have real documentation for this project.
I just wanted to move this out into it's own issue and to add that I have the domain www.pep257.org for that. I have no preference regarding docs technology, be it github pages with sphinx or readthedocs.org or anything else.
I got strange D200 errors when docstring cannot be one-liner.
For example,
def clean(self):
"""
Remove provider and provider hotel from form data if it not supplied.
"""
will produce D200 error.
But if change it to one-liner, like:
def clean(self):
"""Remove provider and provider hotel from form data if it not supplied."""
the line with docstring obviously would be longer than 79 characters, so I get E501 line too long (83 > 79 characters)
error.
There was a new release of pep8 yesterday (Feb 6th, 2015) that added some new checks that pep257 violates (most notably lambda expression assignment). We need to fix these violations for our build to pass.
hello,
I was wondering why a 0.4.1 was advertised on pypi:
https://pypi.python.org/pypi/pep257
altough no corresponding tag is available; last one is 0.3.2 from march 2014
As stated in issue #6, I am currently working on a project where I would like to add pep8 and pep257 conformance into my automated tests. Instead of calling
$ python pep257 <files>
from my tests, it would be a really nice feature if there was a documented Python API for this package, similar to this one.
When running pep257.py on itself, it reports warnings. The warnings are from the test methods which have the PEP-257 specification as docstring. Some of these don't begin with a word that passes the check.
$ ./pep257.py pep257.py
================================================================================
Note: checks are relaxed for scripts (with #!) compared to modules
pep257.py:391:4: First line should be in imperative mood ('Do', not 'Does').
pep257.py:477:4: First line should be in imperative mood ('Do', not 'Does').
pep257.py:580:4: First line should be in imperative mood ('Do', not 'Does').
Parse_all() flags an error if all is not a tuple, whereas all is more commonly a list.
This was mentioned in pull request #19. Creating an issue for this while I remember it.
This can be done fairly easy. Have a look at https://github.com/JensRantil/rewind/blob/develop/rewind/test/test_code.py#L44
I installed pep257 0.3.2 using pip with pip install pep257
, but there is noexecutable in my C:\Python33\Scripts
path.
There is a Python script named pep257
(no extension) in the folder but Windows does not know run that via console. I had added .py
to my PATHEXT env long ago which means entering pep257
into a shell should find it (e.g. subprocess.Popen("pep257", shell=True)
, so I copied the file to another one with that extension. Now my system can find the file but it fails to execute because import pep257
tries to import this very file and searches for main
within, which is obviously not there.
Because of that and the shell restriction all other packages bundle an .exe
that can always be found and pep257 needs one too.
If I check a file containing
class A:
"""Test documentation."""
class B:
pass
I notice that it will not complain that B
does not contain any PyDoc. I guess this is incorrect behaviour?
Not sure, if it is explicitly mentioned anywhere in PEP 257, but seems to be the case.
There's no reason to force documentation for methods such as __str__
, __unicode__
, __repr__
, etc.
I can't seem to find any good examples on the internet concerning meaningful __init__
docstrings. There may be times when there are no parameters, or perhaps documenting the parameters would be helpful.
PEP 257 does say:
Public methods (including the
__init__
constructor) should also have docstrings.
but applying this rule seems unnecessary at times.
This is what makes sense to me:
class Klass:
"""Docstring here."""
def __init__(self, component):
"""
component - The component to model. Can be a name or something else.
"""
self.component = component
But of course, pep257 gives this:
PEP257 Short description should end with a period.
This is what I have ended up doing, but it seems awkward and unnecessary just to ensure pep257 does not complain.
Example:
def __init__(self, component):
"""The constructor.
component - The component to model. Can be the name of the model or a path to a file.
"""
self.component = component
I have tried searching online to see how industry treats it, but it seems almost everyone doesn't document the __init__
unless there is a compelling reason to do so. As an example, see the Error class in pep257. :D
class Error(object):
"""Error in docstring style.
* Stores relevant data about the error,
* provides format for printing an error,
* provides __lt__ method to sort errors.
"""
# options that define how errors are printed
explain = False
range = False
quote = False
def __init__(self, filename, source, docstring, context,
explanation, start=None, end=None):
self.filename = filename
self.source = source
self.docstring = docstring
self.context = context
self.explanation = explanation.strip()
So the question is, can/should something be added/changed in pep257 to avoid this? Is this a problem with the specification, the tool, or perhaps neither?
Any insight you guys have would be great.
The title says it all. I think it would be useful.
pep8 has ~/.config/pep8
.
PyLint has ~/.pylintrc
.
Flake8 has ~/.config/flake8
.
Even PyChecker had ~/.pycheckrc
.
Why can't pep257
have a configuration file ?
It throws an AllError when the first value of the tuple is not in the same line like this:
__all__ = (
'foo', 'bar'
)
pep257 fails to open a file with an unicode arrow:
UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 17236: character maps to <undefined>
This is because Windows uses the cp1252 encoding by default, but my source file is encoded as utf-8.
Instead of just calling open()
on the file, it should detect the correct encoding according to PEP263 and open it with that encoding.
#0 Introduction
In this issue, I'm going to list a number of related features that I feel deserve a clear solution that can't be achieved by solving each one independently. I also suggest a possible solution. *I highly encourage anyone to criticize the features and the solution. Of course everyone is also encouraged to suggest alternative solutions, use cases or related features. In short - show me where I'm wrong.
#1 Features
Right now, the only implemented feature is (2):
pep257 --ignore=D203,D400,D102
#3 Proposed Solution
--select=D100,D202
--ignore=D100,D202
--add-ignore=D100,D202
--add-select=D100,D202
--convention=numpy
--select
, --ignore
and --convention
are mutually exclusive. It's--convention=pep257
was specified.--add-ignore
and --add-select
can only be specified as command line--add-ignore
and --add-select
are not mutually exclusive. However,For the sake of the following use cases, assume that there exists two mutually
exclusive error codes, D101 and D102. PEP257 uses D101 (so it's on by default)
Also assume that there are many more errors of either of these types.
pep257
pep257 --add-select=D104
pep257 --add-ignore=D101 --add-select=D102
pep257 --select=D100,D102
pep257 --convention=numpy --add-select=D103
pep257 --convention=numpy --add-ignore=D104
The following flags should achieve this:
pep257 --convention=numpy --add-select=D101 --add-ignore=D102
Config file:
[pep257]
select = D100,D102,D104
Command line:
pep257 --add-ignore=D104
Config file:
[pep257]
select = D100,D102,D104
Command line:
pep257 --add-select=D103
Config file:
[pep257]
select = D100,D102,D104
Command line:
pep257 --convention=numpy
I tried to use the script version from the "rewrite" branch. It seemed that the error numbers were changed and are not longer in sync with the README. This is expected, but there should be a way to ask the tool to describe all the possible errors.
A possible interface would be:
$ pep257 --error-list
D100: Module is missing docstring.
D101: Class is missing docstring.
...
Where if --explain
is specified as well, the longer description is printed.
It would be great to ignore specific types of violations (for example, the 'class docstrings must have one blank line around them'), and mapping the violation to a specific error code would make this much easier.
I just noticed the https://pypi.python.org/pypi/pep257 hasn't been updated since 2012-08.
flake8 and pep8 interprets values passed to 'ignore' as prefix to ignore. So one can:
pep8 --ignore=W
That will ignore any pep8 ignore.
I wanted to have pep257 to ignore any missing docstrings (D10{1,2,3,4}) by using:
pep257 --ignore=D10
But that would only ignore D10 errors and let D101 and others flow in.
pep8 handles it via startswith():
def ignore_code(self, code)
"check if code should be ignored"
return (code.startswith(self.options.ignore) and
not code.startswith(self.options.select))
...Causes problems on Python systems without curses lib.
Can be easily replaced with:
from:
from curses.ascii import isascii
to :
def isascii(c): return ord(c) <= 127 #Based on from curses.ascii import isascii
Version 0.2.4 is available on PyPI, but there is no corresponding tag on the source code.
If I check
def a():
"""Do something."""
def b():
"""My other help function that's used in a()."""
return 42
I will get the warning
test.py:2:4: PEP257 Return value type should be mentioned.
even though a()
does not return anything.
The pep257.py script contains a number of PEP-257 errors which I assume are intended to demonstrate the functionality.
I want to be able to use the script in an environment where all python scripts (including pep257.py itself) will be automatically verified with pep257.py (and pep8.py) but this isn't possible if the script itself fails :)
Would you accept a pull request that removes these errors?
(The necessary changes are already done on my fork but I need to refactor it to break out some other changes to a separate commit)
I've just written a unittest that checks my pep257 compliance using the API created in issue #7. However, the issue is the checks are taking extremelly long to execute. Here's the output from profiling the test:
ncalls tottime percall cumtime percall filename:lineno(function)
3/1 0.000 0.000 30.775 30.775 /Users/jens/Development/src/my_projects/rewind/src/nose-1.1.2-py2.7.egg/nose/suite.py:175(__call__)
3/1 0.000 0.000 30.775 30.775 /Users/jens/Development/src/my_projects/rewind/src/nose-1.1.2-py2.7.egg/nose/suite.py:196(run)
2 0.000 0.000 30.774 15.387 /Users/jens/Development/src/my_projects/rewind/src/nose-1.1.2-py2.7.egg/nose/case.py:44(__call__)
2 0.000 0.000 30.774 15.387 /Users/jens/Development/src/my_projects/rewind/src/nose-1.1.2-py2.7.egg/nose/case.py:115(run)
2 0.000 0.000 30.773 15.386 /Users/jens/Development/src/my_projects/rewind/src/nose-1.1.2-py2.7.egg/nose/case.py:142(runTest)
2 0.000 0.000 30.773 15.386 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py:375(__call__)
2 0.000 0.000 30.773 15.386 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py:286(run)
1 0.000 0.000 30.136 30.136 /Users/jens/Development/src/my_projects/rewind/src/rewind/test/test_code.py:30(testPep257Conformance)
1 0.000 0.000 30.134 30.134 /Users/jens/Development/src/my_projects/rewind/lib/python2.7/site-packages/pep257.py:320(check_files)
336/6 0.004 0.000 30.133 5.022 /Users/jens/Development/src/my_projects/rewind/lib/python2.7/site-packages/pep257.py:114(<lambda>)
118 0.011 0.000 30.133 0.255 /Users/jens/Development/src/my_projects/rewind/lib/python2.7/site-packages/pep257.py:304(check_source)
96 0.001 0.000 23.562 0.245 /Users/jens/Development/src/my_projects/rewind/lib/python2.7/site-packages/pep257.py:223(parse_contexts)
1768 0.055 0.000 17.256 0.010 /Users/jens/Development/src/my_projects/rewind/lib/python2.7/site-packages/pep257.py:208(parse_methods)
My test is written like so:
def testPep257Conformance(self):
"""Test that we conform to PEP257."""
pyfiles = self._get_all_pyfiles()
errors = pep257.check_files(pyfiles)
if errors:
print("There were errors:")
for error in errors:
print(error)
self.assertEquals(len(errors), 0)
and the total number of lines of code for the six Python modules are 1957 LOC.
I have the following docstring.
@property
def file_path(self):
'''Alias for consistency with the rest of pocketlint.'''
The error is
142: D401: First line should be imperative: 'Alia', not 'Alias'
While the intent is noble, I think that the current implementation is not helpful.
Is there anyone using this check in production code?
If a check could not be done, I prefer to not try to automate it as it is not fun to maintain a list of ignored values..
Thanks!
pep8 supports both # noqa and # nopep8 at the end of a line to silence errors regarding that line.
It would be nice if pep257 had a similar capability to silence errors for a specific docstring, so that the entire file doesnt need to be excluded , or the same error in all files doesnt need to be excluded.
e.g. adding '# nopep257' after the docstring
When reporting a D401, the line number returned is the line of the function, not the line number for the docstring
This is useful to get a metric for code conformance.
It will also help marking progress when fixing a large code base with many violations.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.