The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
ignore_raise
configuration option, or command-line option.
Thanks to @palt0 for the pull request!ignore_regex
as a command-line option (this already existed as a
configuration option, but I overlooked it as a command-line option.) Thanks
to @saroad2 for the pull request!enable
option from the configuration file, so that disabled-by-default
errors can be shown. Thanks to @palt0 for the pull request!Dockerfiles for testing each supported Python version. Also added a tox section to allow for testing these dockerfiles. To build the images, you can first do
make -C docker-build
then you can run
tox -e docker
And it will run the unit tests against Python3.5 to Python3.8.
Nested functions/methods. We should now handle nested functions/methods explicitly. Previously, some attributes (such as returns, etc.) would leak through nested functions into their parents. (Since we were just walking the tree and looking for the presence of certain tokens.) This also allowed for a nice refactoring of how we walk through/collect data on the function ast.
Exception handlers with named instances now have the correct type reported with bare raises. Previously, if you had something like
def inverse(x):
try:
return 1 / x
except ZeroDivisionError as zde:
raise
darglint would incorrectly drop the ZeroDivisionError
as a possible
error source when examining the function. This was due to named exception
handlers being handled differently from other exceptions. (The name had
to be stored in case a user did something like raise err
.)
Remove variables section from the numpy supported sections. Thanks to @skarzi for the pull request!
IndentError
when a
line is underindented in an item definition. This makes
troubleshooting incorrect indentation easier. (Previously,
it would have just failed to parse.)ERROR
, and the default log level is CRITICAL
.
If darglint doesn't act as expeced, then, the user could pass
the --log-level
flag to rerun and see if an expectation was
missed.AssertionError
for functions which contain an assert
statement. Previously, this would result in an excess raises
error.Qualified exceptions in a raise section were not being
handled correctly by the FunctionDescription
class.
So, if you had a catch statement like,
def finish_me(): try: raise requests.exceptions.ProxyError() except requests.exceptions.ProxyError: raise
It wouldn't have been handled correctly. That is, if
you documented requests.exceptions.ProxyError
in the
docstring, darglint would throw an error. This change
resolves the situation, at lest somewhat. It expects
the documented exception and the caught exception to
match exactly.
Implicitly raised exceptions which are rethrown was also not handled. So, for example, if you had:
def throwing_up(): """Throws up.
Raises:
ProxyError: If failed to yarf.
"""
try:
proxy_puke()
except ProxyError:
raise
Darglint would report an error. It no longer reports an error in this case. See Issue #88 and Issue #68.
Handle the else branch of try-except statements when searching for raise statements during analysis.
Handle empty type in Google-style arguments (previously raised an exception, now it's a darglint error with a description.)
Handle exceptions raised by the Python module, ast.
Handle a bare raise statement within an exception handler. For example, if you have
try: raise SyntaxError('Wrong!') except SyntaxError: raise
Then you know that you really have to document a syntax error.
raises
statement.
Now analysis builds contexts around try-except blocks, and
accounts for the catch-and-throw pattern. Anything unusual
will still raise an error, but it's more robust than previously.:return x: Explanation.
where x
is the type returned.
However, this should really only be handled by the :rtype:
section. This incorrect return type was labelled using the
same node name as the normal return type, leading to an
assertion being raised. The inline return type was removed.DAR104
which checks for the presence of types in the docstring.ast
module. See Issue #46.A bin/ folder to hold various development utilities for darglint.
Currently, it holds bnf_to_cnf
(a utility to convert BNF grammars to
CNF grammars), and doc_extract
(a utility to extract docstrings from
repositories, and annotate them for use in integration tests.)
A (crappy) integration test framework. Test fixtures are ignored in git, since the integration tests are only relevant for local development (and even then, mostly just release). The integration tests are as follows:
goldens.py: Tests against goldens for individual docstrings. This
attempts to ensure that parsed docstrings always contain the expected
sections after development. Goldens are generated using the doc_extract
utility in the bin/ folder.
grammar_size.py: Tests that the grammar size doesn't increase significantly. Larger grammars will result in longer parse times, and it could be relatively easy to accidentally introduce a much larger grammar.
performance.py: Tests performance of the parser against individual docstrings to make sure we don't introduce a performance regression. Also tests performance for individual files in some repositories.
TODO: We still need to add some tests against multiple configurations, and against entire repositories.
Incorrect configuration for flake8. See Issue #35.
Incorrect check for strictness options long and full. See Issue #37.
Thanks to sobolevn for these fixes!
Minimum strictness configuration option. You can now specify a minimum amount of strictness to have when checking docstrings. Strictness does not affect whether the docstring will be checked or not; it only changes the amount of checking which is done. For example, if your config file looks like
[darglint] strictness=short
Then the following would pass with no errors:
def double(x): """Returns the number, multiplied by two.""" return x * 2
The following levels of strictness are available:
short: One-line descriptions are acceptable; anything more and the docstring will be fully checked.
long: One-line descriptions and descriptions without arguments/returns/yields/etc. sections will be allowed. Anything more, and the docstring will be fully checked.
full: (Default) Docstrings will be fully checked.
Try-block handlers were not included when tranversing the function ast. This meant that return or yield statements in the except-block or else block would not register, and an exception would be raised.
Allow indents in types. This lets us handle line continuation for type signatures.
Fix appropriate noqas not hiding S001. (Because the docstring is never actually parsed when it's a syntax error.)
.py
.Simplified the interface for the Docstring base class. This should make modifications easier, and should ensure that the same value is returned consistently between Google and Sphinx styles.
This comes at the cost of a slightly more complicated function signature
for the functions which remain. However, the single parameter which
is passed to the functions (an enumeration named Sections
), can
(and should) be used everywhere the NodeType
enumeration is currently
used (outside of the actual parsing step.) This will effectively create
a firewall around the parsing step.
:var <name>:
, and the name doesn't exist in
the actual function, an error will be issued.:returns:
must be the last items in the docstring,
must be together, and any multiple lines must be indented with four spaces.Token
s. The line numbers are added
and incremented in the lex()
function.Message templates for error reports based on Pylint's syntax. The message template uses a normal Python format string with named arguments. For example, the default format string for an error message is '{path}:{obj}:{line}: {msg_id}: {msg}'.
This is passed to the linter by a command-line argument. For example, to get only the path, line number, and error code, we could pass something like the following:
darglint -m "{path}:{line} -> {msg_id}" *.py
This value can also be specified in the configuration file
as the value, message_template
. For example, the above
template could have been specified in the configuration
as
[darglint]
message_template={path}:{line} -> {msg_id}
Added support for Python3.5. Probably earlier versions of Python can also be supported, but they need to be tested, first.
Added tox script for running tests against all environments. To run the tests, make sure the test dependencies are installed, and run
tox
Allow global noqa statements in docstring. If we have a docstring which we would like to ignore (say, because it has a different format), then we can ignore it either by adding "# noqa" or "# noqa: *" to it.
For example, the following program would raise an exception that there is a missing "Returns" section:
def is_palindrome(word):
"""True if the word is a palindrome.
# noqa
"""
return word == word[::-1]
However, since there is a global noqa statement, all errors are ignored.
IntegrityChecker
.) The parser cannot raise
specific error messages, then, since it can't access the function.
So, currently, the ParserException
takes an optional, more
specific error, which can be created by the IntegrityChecker
.ast
module does not return functions
in any particular order, but tests were relying on a specific order.)def walk(root):
"""Walk the tree, yielding active nodes.
Args:
root: The root of the tree.
Yields:
Active nodes.
"""
def skip(node):
return node.inactive
queue = deque()
queue.append(root)
while len(queue) > 0:
curr = queue.pop()
if skip(curr):
continue
yield curr
queue.extend(curr.children)
This function previously would have raised a missing return error (I201), and would have required a noqa. That is no longer the case.
ParserException
is thrown if there is no colon after the type annotation
or argument/exception in the description.
For example, the following function would raise the ParserException
:
def hello(name):
"""Say hello to the person.
Args:
name: The name of the person to
whom we are saying hello.
"""
print('hello, {}'.format(name))
Added optional hint to the function _expect_type
in darglint/parse.py
.
This will be displayed after the default message. We'll have to add
an option for hints in the configuration, and show or hide them accordingly.
Added check to ensure that a description exists after an item in the
argument descriptions or exception descriptions (or any multi-section).
At some point, this should probably be optional, but it is currently
raises a ParserException
(which is too general to really want to
exclude.)
GenericSyntaxError
for any ParserException
s which are raised when
parsing. Ideally, we would add the offset for the lines in the
docstring so that we could get a more accurate indication of where the
actual error occurred. (This would be useful for when we integrate with
ALE or Syntastic or something.)get_logger()
function to the config file. This will help us to get a
fully configured logger. It'll also be a nice way to request a preconfigured
logger (say, "darglint.parser" or something if we want to log from the
parser.) Then we could parse the same configuration to every logger.def do_something_dangerous():
try:
dangerous_action()
except CertainDoom:
raise
This would previously caused an error. Now, no checks are made for it. A "TODO" was left in the code as a reminder that we could handle this better in the future.
Added configuration files. Configuration files use the normal Python
configparser
and TOML format. Configuration files for darglint
should have one of the following names:
.darglint
setup.cfg
tox.ini
In addition, the settings for darglint must be in a section described
by [darglint]
. The configuration takes a single key, ignore
,
and a list of error codes to ignore as a value. For example, if we
would like to ignore the errors "I101" and "I102", then we would
could write the following section in our tox.ini file:
[darglint]
ignore=I101,I102
darglint will look for a config file stating at the current directory and working its way up to the root directory.
Simplified error messages.
There are now only two verbosity levels, 1 and 2. I've kept it as an integer argument so that, in the future, we can add other levels if necessary. The default level, now, is 1. At that level, the error message is something like:
::: :
Where message is an abbreviated version. (It uses symbols primarily. For example "- word" denotes a missing parameter in a docstring. "+ word" denotes an extra parameter in the docstring.
Using a level 2 verbosity also prints out the general error message. (This describes what the error is. So, if level 1 is too cryptic, we can switch to level 2.) This will look like:
::: : :
This gets pretty long, so that's why it's not the default.
Verifies types specified in the docstring against type hints
on the function. Also added noqa
for these errors.
For example, if we have a function with a mismatched type, such as:
def mismatched_type(x: int) -> str:
"""Return the string representation of the number.
Args:
x (float): The float to represent.
Returns:
str: The string representation of the number.
"""
return str(x)
Then it would raise a TypeMismatchError
, since the parameter,
x
, has a type hint of int
, while the docstring documents
it as being of type float
. We could prevent this error
by either adding # noqa: I103
or # noqa: I103 x
.
Checks for a "Yields" section added. If a function contains
either the yield
or yield from
keywords, darglint will
expect to find a "Yields" section in the docstring.
Checks for a "Raises" section added. If a function raises an exception, then the raises section should document the exact exception or error raised. Will also warn if the raises section documents exceptions not explicitly raised in the function or method. (This feature will be disabled by default.)
It may be possible to check the super classes of a given error, to make more general descriptions in the raises section. That would prevent the interface from leaking implementation details. However, that would entail a good deal more work. This may be implemented at a later date, but for now, if you're doing that, then you should just disable the checks for exception/error raising.
A Docstring
class. This class now handles all of the parsing for
docstrings, and stores the attributes found from the docstring. It
is the docstring corollary FunctionDescription
.
It's attributes are either strings (Docstring.returns_description
,
Docstring.yields_description
, Docstring.short_description
,
Docstring.long_description
), or dictionaries containing
arguments/exceptions and their descriptions (
Docstring.arguments_descriptions
, Docstring.raises_descriptions
).
We can now ignore certain errors using noqa
. The syntax for
noqa
is very similar to that used for pycodestyle and other
linters, with the exception that noqa
, here, can take an argument.
Let us say that we want to ignore a missing return statement in the following docstring:
def we_dont_want_a_returns_section():
"""Return the value, 3.
# noqa: I201
"""
return 3
We put the noqa
anywhere in the top level of the docstring.
However, this won't work if we are missing something more specific,
like a parameter. We may not want to ignore all missing parameters,
either, just one particular one. For example, we may be writing a
function that takes a class instance as self. (Say, in a bound celery
task.) Then we would do something like:
def a_bound_function(self, arg1):
"""Do something interesting.
Args:
arg1: The first argument.
# noqa: I101 arg1
"""
arg1.execute(self)
So, the argument comes to the right of the error.
We may also want to mark excess documentation as being okay. For example,
we may not want to explicitly catch and raise a ZeroDivisionError
. We
could do the following:
def always_raises_exception(x):
"""Raise a zero division error or type error.o
Args:
x: The argument which could be a number or could not be.
Raises:
ZeroDivisionError: If x is a number. # noqa: I402
TypeError: If x is not a number. # noqa: I402
"""
x / 0
So, in this case, the argument for noqa
is really all the way to
the left. (Or whatever description we are parsing.) We could also
have put it on its own line, as # noqa: I402 ZeroDivisionError
.
Command line interface. There is currently only a single option, verbosity, and a single multi-value argument, files. Help for the command can be accessed using
darglint -h
Example Usage:
darglint -v 3 darglint/*.py
This runs a documentation check on all of the internal modules for darglint, with a verbosity level of 3 (the highest.)
Changelog.
Handling for methods. Checks for whether the method is a static method or a class method. Doesn't prompt for documentation for "self", or "cls" when not appropriate.
Change format for error messages to be less verbose. The format is now:
<function/method name>
- <missing argument>
+ <extraneous argument>
darglint
should only care about whether a docstring is up to
date, not whether it is present or not.Began project. Added check of function definitions. Buggy and doesn't handle many options.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。