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

Empty lines do not break options sections. #339

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions docopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,15 @@ def parse_defaults(doc):


def parse_section(name, source):
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
re.IGNORECASE | re.MULTILINE)
pattern = re.compile(r'''
^( # A section begins at start of a line and consists of:
.*{}.* # - a line that contains the section's name; and
(?: # - several
\n+[ \t].* # indented lines possibly separated by empty lines.
)*
)$ # The section ends at the end of a line.
'''.format(name),
re.IGNORECASE | re.MULTILINE | re.VERBOSE)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[^\n] were replaced with just . because according to the Regular Expression Syntax:

(Dot.) In the default mode, this matches any character except a newline.

return [s.strip() for s in pattern.findall(source)]


Expand Down
63 changes: 34 additions & 29 deletions test_docopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,11 @@ def test_commands():


def test_formal_usage():
doc = """
Usage: prog [-hv] ARG
prog N M

prog is a program."""
doc = '\n'.join(('Usage: prog [-hv] ARG',
' prog N M',
'prog is a program.'))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The join looks like a more sane way to have properly indented multiline strings.

usage, = parse_section('usage:', doc)
assert usage == "Usage: prog [-hv] ARG\n prog N M"
assert usage == "Usage: prog [-hv] ARG\n prog N M"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spaces were removed because of previous wrong indentation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, this line was indented and therefore it was a part of the 'Usage' section. If the emty line is removed and lines are aligned (they all are already indented) then this section could be rewritten in the following way:

Usage: prog [-hv] ARG
       prog N M
       prog is a program.

which looks like a wrong description.

assert formal_usage(usage) == "( [-hv] ARG ) | ( N M )"


Expand Down Expand Up @@ -389,23 +387,22 @@ def test_allow_double_dash():


def test_docopt():
doc = '''Usage: prog [-v] A

Options: -v Be verbose.'''
doc = '\n'.join(('Usage: prog [-v] A',
'',
'Options: -v Be verbose.'))
assert docopt(doc, 'arg') == {'-v': False, 'A': 'arg'}
assert docopt(doc, '-v arg') == {'-v': True, 'A': 'arg'}

doc = """Usage: prog [-vqr] [FILE]
prog INPUT OUTPUT
prog --help
doc = '\n'.join(('Usage: prog [-vqr] [FILE]',
' prog INPUT OUTPUT',
' prog --help',
'',
'Options:',
' -v print status messages',
' -q report only file names',
' -r show all occurrences of the same error',
' --help'))

Options:
-v print status messages
-q report only file names
-r show all occurrences of the same error
--help

"""
a = docopt(doc, '-v file.py')
assert a == {'-v': True, '-q': False, '-r': False, '--help': False,
'FILE': 'file.py', 'INPUT': None, 'OUTPUT': None}
Expand All @@ -431,7 +428,7 @@ def test_language_errors():
with raises(DocoptLanguageError):
docopt('no usage with colon here')
with raises(DocoptLanguageError):
docopt('usage: here \n\n and again usage: here')
docopt('first usage: here \n\nsecond usage: here')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of a space before 'and' the section looked like:

usage: here 

 and again usage: here

So, the second line was indented and therefore considered to be a part of the first section.



def test_issue_40():
Expand Down Expand Up @@ -490,19 +487,27 @@ def test_any_options_parameter():


def test_default_value_for_positional_arguments():
doc = """Usage: prog [--data=<data>...]\n
Options:\n\t-d --data=<arg> Input data [default: x]
"""
doc = '\n'.join(('Usage: prog [--data=<data>...]',
'',
'Options:'
' -d --data=<arg> Input data [default: x]'))

a = docopt(doc, '')
assert a == {'--data': ['x']}
doc = """Usage: prog [--data=<data>...]\n
Options:\n\t-d --data=<arg> Input data [default: x y]
"""

doc = '\n'.join(('Usage: prog [--data=<data>...]',
''
'Options:',
' -d --data=<arg> Input data [default: x y]'))

a = docopt(doc, '')
assert a == {'--data': ['x', 'y']}
doc = """Usage: prog [--data=<data>...]\n
Options:\n\t-d --data=<arg> Input data [default: x y]
"""

doc = '\n'.join(('Usage: prog [--data=<data>...]',
'',
'Options:',
' -d --data=<arg> Input data [default: x y]'))

a = docopt(doc, '--data=this')
assert a == {'--data': ['this']}

Expand Down
18 changes: 18 additions & 0 deletions testcases.docopt
Original file line number Diff line number Diff line change
Expand Up @@ -955,3 +955,21 @@ other options:
"""
$ prog --baz --egg
{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}


# An empty line must not break an options section.
r"""
Usage: prog [options]

Options:
--before-empty-lines An option before empty lines.


--after-empty-lines An option after empty lines.
"""

$ prog --before-empty-lines
{"--before-empty-lines": true, "--after-empty-lines": false}

$ prog --after-empty-line
{"--before-empty-lines": false, "--after-empty-lines": true}