Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docopt 0.6.2 compat squashed #38

Closed
wants to merge 14 commits into from

Conversation

NickCrews
Copy link
Contributor

Squashed version of #36

@codecov
Copy link

codecov bot commented Sep 8, 2022

Codecov Report

Merging #38 (abf13dd) into master (6b8f84e) will decrease coverage by 0.00%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master      #38      +/-   ##
==========================================
- Coverage   99.79%   99.79%   -0.01%     
==========================================
  Files           1        1              
  Lines         492      487       -5     
==========================================
- Hits          491      486       -5     
  Misses          1        1              
Impacted Files Coverage Δ
docopt/__init__.py 99.79% <100.00%> (-0.01%) ⬇️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@NickCrews
Copy link
Contributor Author

@h4l is this good to be merged?

@h4l
Copy link
Contributor

h4l commented Sep 8, 2022

@NickCrews Yes, all good for me, just as long as you're good with the option description fix #36 (comment)

Edit: although I guess this branch isn't rebased on the current master, which I could do.

It was throwing an error due to the options: section occurring in
usage:, but the test was passing because the message of the exception
was not checked.
parse_docstring_sections() divides the docstring into the main
non-overlapping sections that are to be further analysed. These are
text before the usage, the usage header ("usage:" or similar), the usage
body (" proc [options]") and text following the usage.

The intention of this partitioning is to facilitate restoring the option
description parsing behaviour of the last stable docopt release (0.6.2),
while retaining the current improved behaviour of not requiring a blank
line after the usage: section; and also removing a small quirk in the
0.6.2 parser, which is that option-defaults can occur before the usage:
section. (But this partitioning provides access to the text before the
usage section, so this behaviour could be retained if desired.)
parse_options() parses option descriptions in a way that is compatible
with docopt 0.6.2, while also compatible with docopt-ng's current
behaviour.

The differences are:

  - docopt-ng requires option descriptions to be in an "options:"
    section, docopt allows them to be anywhere outside the "usage:"
    section.
  - docopt-ng requires options descriptions have leading whitespace,
    docopt allows them to start at column 0.
  - docopt-ng allows options descriptions to begin on the same line as
    a section heading, docopt does not. e.g. `options: --foo` is OK with
    docopt-ng.

parse_options() parses options following either docopt or docopt-ng's
behaviour. Although it expects the `docstring` argument to be a
sub-section of the overall docstring, so the caller is in control of
where in the docstring options are parsed from.
This commit uses parse_docstring_sections() and parse_options() to
parse docstrings accepted by docopt 0.6.2, while retaining docopt-ng's
improvements to supported syntax.

Currently, docopt-ng parses option-defaults using a strategy that was in
docopt's master branch, but considered unstable by the author, and was
not released in docopt. It looks for option descriptions in an
"options:" section, which is ended on the first blank line. This has
the side-effect that options defined in a man-page style — with blank
lines in-between — are not found. Neither are options outside an
options: section (docopt allows options to follow the usage with no
section heading).

parse_docstring_sections() is used to separate the usage section from
the rest of the docstring. The text before the usage is ignored. The
usage body (without its header) is parsed for the argument pattern and
the usage header with its body is used to print the usage summary help.
The text following the usage is parsed for options descriptions, using
parse_options(), which supports option the description syntax of both
docopt and the current docopt-ng.

Note that docopt 0.6.2 recognises option descriptions in the text
prior to the usage section, but this change does not, as it seems like
an unintended side-effect of the previous parser's implementation, and
seems unlikely to be used in practice.

The testcases have two cases added for docopt 0.6.2 compatibility.

This fixes jazzband#33
This implements Nick's suggestion from jazzband#36. When generating tests from
testcases.docopt, we now raise an error if an example doc has no
testcases following it to actually exercise the example.

Also, tests with invalid JSON testcases are reported using the same
error reporting mechanism.
This fixes a pre-existing bug in docopt-ng that wasn't previously
triggered by a test. Options in the options: section without a
description on the same line and with content on the following line
(e.g. a line-wrapped description) would be parsed as if the content on
the following line was part of the option name & arguments.

Option.parse() now ends the option name & arguments section on the end
of the line, not just on two consecutive spaces.
It's a bit of an obscure and non-obvious regex feature. The regex uses
a negative lookahead assertion now, which is still a little odd, but
it's clearer I think.
The usage section heading now needs to have a word break before usage:,
so e.g sausage: doesn't match as a usage: section.
lint_docstring() now checks for the usage_body being empty, and fails
with a message indicating this.
parse_docstring_sections() is no longer responsible for rejecting docs
with empty usage sections. Previously it did so to some extent, but
failed to reject whitespace-only usage bodies. lint_docstring() now
rejects empty usage bodies, which allows the regex's usage_body group to
be simplified.

The removed test for empty usage bodies is tested via
test_lint_docstring.
Docopt 0.6.2 allows option descriptions anywhere in the doc, not just
after the usage: section. With this change, we parse both the section
prior to the usage: and the section after for option descriptions.
This adds another case for test_parse_options demonstrating how
parse_options() parses docs which contain both options and text that
mentions options that should not be interpreted as options.

This includes an example (the '-b' option) where we do currently parse
an option mentioned in prose as a real option. In principle we could fix
this, but it's here for now to document current behaviour. And it's not
hard to work around when writing a usage doc - just need to adjust where
a line is wrapped.
@h4l h4l force-pushed the docopt-0-6-2-compat_squashed branch from 1cdb7de to abf13dd Compare September 8, 2022 17:23
@h4l
Copy link
Contributor

h4l commented Sep 8, 2022

OK, that's it rebased on the current master. Could also force push this to the existing branch to merge that PR if you like. I think you've got permission to do that if you want to.

@NickCrews
Copy link
Contributor Author

Superseded by the merged #36

@NickCrews NickCrews closed this Sep 8, 2022
@h4l h4l deleted the docopt-0-6-2-compat_squashed branch September 9, 2022 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants