Compare commits
No commits in common. "main" and "v0.1.1" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -138,4 +138,3 @@ dmypy.json
|
|||||||
# Cython debug symbols
|
# Cython debug symbols
|
||||||
cython_debug/
|
cython_debug/
|
||||||
|
|
||||||
.vscode
|
|
||||||
|
|||||||
17
README.md
17
README.md
@ -29,7 +29,7 @@ args, kwargs = parse_args(argv=['pargv.py', '--name=pargv'])
|
|||||||
|
|
||||||
# Specification
|
# Specification
|
||||||
|
|
||||||
`parse_args` parses arguments in the following way, assuming the following command line arguments (`sys.argv`): `['/pargv/pargv.py', 'command', 'positional', '--flag', '--optional=value', 'test', '--output-file', 'filename', '-ab=one', 'two']`
|
`parse_args` parses arguments in the following way, assuming the following command line arguments (`sys.argv`): `['/pargv/pargv.py', 'command', 'positional', '--flag', '--optional=value', 'test', '--output-file', 'filename', '-flg', 'name', 'name2']`
|
||||||
|
|
||||||
By calling `args, kwargs = parse_args()`, this would return the following list and dict:
|
By calling `args, kwargs = parse_args()`, this would return the following list and dict:
|
||||||
|
|
||||||
@ -38,9 +38,10 @@ args = ['/pargv/pargv.py', 'command', 'positional']
|
|||||||
kwargs = {
|
kwargs = {
|
||||||
'flag': True,
|
'flag': True,
|
||||||
'optional': ['value', 'test'],
|
'optional': ['value', 'test'],
|
||||||
'output_file': 'filename',
|
'output_file': ['filename'],
|
||||||
'a': True,
|
'f': True,
|
||||||
'b': ['one', 'two'],
|
'l': True,
|
||||||
|
'g': ['name', 'name2'],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -48,8 +49,6 @@ kwargs = {
|
|||||||
|
|
||||||
- All arguments before the first option (starting with a hyphen) are considered positional arguments (`args`)
|
- All arguments before the first option (starting with a hyphen) are considered positional arguments (`args`)
|
||||||
- All other arguments are considered optional keyword arguments (`kwargs`)
|
- All other arguments are considered optional keyword arguments (`kwargs`)
|
||||||
- Optional arguments without leading hyphens are considered as values to preceding keyword arguments
|
- Optional arguments without leading hyphens are considered as values to preceding keyword arguments and saved as list
|
||||||
- One value of an option is stored as a string, multiple values are stored as a list
|
- Flags are recorded with the value `True` in the dict
|
||||||
- Flags are stored with the value `True` in the dict
|
- Up to 2 leading hyphens are stripped from options, all other hyphens are converted into underscores (`---test-this-` would become `_test_this_`)
|
||||||
- Up to 2 leading hyphens are stripped from options, all other hyphens are converted into underscores (`---test-this-` would become the key `_test_this_` in the dict)
|
|
||||||
- For multiple short options such as `-vao=file.ext` or `-vao file.ext`, the last option (`o`) is set to the specified value, while other options (`v` and `a`) are set to `True`.
|
|
||||||
|
|||||||
45
pargv.py
45
pargv.py
@ -1,9 +1,6 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
__version__ = '0.2.1'
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args(argv=None):
|
def parse_args(argv=None):
|
||||||
"""
|
"""
|
||||||
Returns a tuple of (args, kwargs) from a given list of command line arguments.
|
Returns a tuple of (args, kwargs) from a given list of command line arguments.
|
||||||
@ -15,32 +12,30 @@ def parse_args(argv=None):
|
|||||||
for arg in argv:
|
for arg in argv:
|
||||||
if arg.startswith('-'):
|
if arg.startswith('-'):
|
||||||
break
|
break
|
||||||
args.append(arg.replace('-', '_'))
|
args.append(arg)
|
||||||
|
argv = argv[len(args):]
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
value = None
|
values = []
|
||||||
for arg in argv[len(args):]:
|
for arg in argv:
|
||||||
|
|
||||||
if not arg.startswith('-'):
|
if not arg.startswith('-'):
|
||||||
if isinstance(kwargs[key], bool):
|
values.append(arg)
|
||||||
kwargs[key] = arg
|
else:
|
||||||
elif isinstance(kwargs[key], str):
|
if len(values):
|
||||||
kwargs[key] = [kwargs[key]] + [arg]
|
kwargs[key] = values
|
||||||
elif isinstance(kwargs[key], list):
|
values = []
|
||||||
kwargs[key].append(arg)
|
|
||||||
continue
|
|
||||||
|
|
||||||
key = arg[:2].lstrip('-') + arg[2:].replace('-', '_')
|
key = arg[:2].lstrip('-') + arg[2:].replace('-', '_')
|
||||||
|
if arg.startswith('--'):
|
||||||
if '=' in key:
|
if '=' in arg:
|
||||||
key, value = key.split('=')
|
key, value = key.split('=')
|
||||||
|
values.append(value)
|
||||||
if not arg.startswith('--'):
|
kwargs[key] = values
|
||||||
for k in key[:-1]:
|
else:
|
||||||
|
kwargs[key] = True
|
||||||
|
elif arg.startswith('-'):
|
||||||
|
for k in key:
|
||||||
kwargs[k] = True
|
kwargs[k] = True
|
||||||
key = key[-1]
|
key = arg[-1]
|
||||||
|
if len(values):
|
||||||
kwargs[key] = value if value else True
|
kwargs[key] = values
|
||||||
value = None
|
|
||||||
|
|
||||||
return (args, kwargs)
|
return (args, kwargs)
|
||||||
|
|||||||
2
setup.py
2
setup.py
@ -6,7 +6,7 @@ with open('README.md') as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='pargv',
|
name='pargv',
|
||||||
version='0.2.1',
|
version='0.1.1',
|
||||||
description='Parse command line arguments into a list of args and a dict of kwargs.',
|
description='Parse command line arguments into a list of args and a dict of kwargs.',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
|
|||||||
@ -6,58 +6,87 @@ from pargv import parse_args
|
|||||||
|
|
||||||
def test_no_argv():
|
def test_no_argv():
|
||||||
with mock.patch('sys.argv', []):
|
with mock.patch('sys.argv', []):
|
||||||
assert parse_args() == ([], {})
|
args, kwargs = parse_args()
|
||||||
|
assert args == []
|
||||||
|
assert kwargs == {}
|
||||||
|
|
||||||
|
|
||||||
def test_use_sys_argv_by_default():
|
def test_use_sys_argv_by_default():
|
||||||
with mock.patch('sys.argv', ['argument', '--flag']):
|
with mock.patch('sys.argv', ['app', 'command', '--option=one', 'two', '--flag', '-io']):
|
||||||
assert parse_args() == (['argument'], {'flag': True})
|
args, kwargs = parse_args()
|
||||||
|
assert args == ['app', 'command']
|
||||||
|
assert kwargs == {
|
||||||
|
'option': ['one', 'two'],
|
||||||
|
'flag': True,
|
||||||
|
'i': True,
|
||||||
|
'o': True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_single_positional_argument():
|
def test_single_positional_argument():
|
||||||
assert parse_args(['argument']) == (['argument'], {})
|
args, kwargs = parse_args(['app'])
|
||||||
|
assert args == ['app']
|
||||||
|
assert kwargs == {}
|
||||||
|
|
||||||
def test_single_positional_argument_with_underscore():
|
|
||||||
assert parse_args(['the-argument']) == (['the_argument'], {})
|
|
||||||
assert parse_args(['a-b']) == (['a_b'], {})
|
|
||||||
|
|
||||||
def test_optional_argument_with_underscore():
|
|
||||||
assert parse_args(['--a-b']) == ([], {'a_b': True})
|
|
||||||
|
|
||||||
def test_positional_arguments():
|
def test_positional_arguments():
|
||||||
assert parse_args(['argument', 'command']) == (['argument', 'command'], {})
|
args, kwargs = parse_args(['app', 'command'])
|
||||||
|
assert args == ['app', 'command']
|
||||||
|
assert kwargs == {}
|
||||||
|
|
||||||
|
|
||||||
def test_one_positional_and_optional_argument():
|
def test_one_positional_and_optional_argument():
|
||||||
assert parse_args(['argument', '--help']) == (['argument'], {'help': True})
|
args, kwargs = parse_args(['app', '--help'])
|
||||||
|
assert args == ['app']
|
||||||
|
assert kwargs == {'help': True}
|
||||||
|
|
||||||
def test_one_positional_and_optional_argument_with_values():
|
|
||||||
assert parse_args(['argument', '--amount=2', '3']) == (['argument'], {'amount': ['2', '3']})
|
|
||||||
|
|
||||||
def test_short_arg_with_single_option():
|
def test_positional_and_optional_arguments():
|
||||||
assert parse_args(['-a', 'b', '--abc', 'd']) == ([], {'a': 'b', 'abc': 'd'})
|
args, kwargs = parse_args(['app', 'command', '--inputfile', '--outputfile'])
|
||||||
|
assert args == ['app', 'command']
|
||||||
|
assert kwargs == {
|
||||||
|
'inputfile': True,
|
||||||
|
'outputfile': True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_short_arg_with_multiple_options():
|
def test_short_arg_with_multiple_options():
|
||||||
assert parse_args(['-i', 'a', 'b']) == ([], {'i': ['a', 'b']})
|
args, kwargs = parse_args(['-a', '-i', 'a', 'b'])
|
||||||
|
assert args == []
|
||||||
|
assert kwargs == {
|
||||||
|
'a': True,
|
||||||
|
'i': ['a', 'b']
|
||||||
|
}
|
||||||
|
|
||||||
def test_short_args_with_equals():
|
|
||||||
assert parse_args(['-ab=c']) == ([], {'a': True, 'b': 'c'})
|
|
||||||
assert parse_args(['-ab=c', 'd']) == ([], {'a': True, 'b': ['c', 'd']})
|
|
||||||
|
|
||||||
def test_long_args_with_equals():
|
def test_long_args_with_equals():
|
||||||
assert parse_args(['--input-file=a.py']) == ([], {'input_file': 'a.py'})
|
args, kwargs = parse_args(['--input-file=a.py', '--output-file=b.py'])
|
||||||
|
assert args == []
|
||||||
|
assert kwargs == {
|
||||||
|
'input_file': ['a.py'],
|
||||||
|
'output_file': ['b.py']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_unintended_hyphen():
|
def test_unintended_hyphen():
|
||||||
assert parse_args(['---triple-hyphen-']) == ([], {'_triple_hyphen_': True})
|
args, kwargs = parse_args(['---triple-hyphen-'])
|
||||||
|
assert args == []
|
||||||
|
assert kwargs == {'_triple_hyphen_': True}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('argv, args, kwargs', ((
|
@pytest.mark.parametrize('argv, args, kwargs', ((
|
||||||
['/pargv/pargv.py', 'command', 'positional', '--flag', '--optional=value', 'test', '--output-file', 'filename', '-flg=name', 'name2'],
|
['/pargv/pargv.py', 'command', 'positional', '--flag', '--optional=value', 'test', '--output-file', 'filename', '-flg', 'name', 'name2'],
|
||||||
['/pargv/pargv.py', 'command', 'positional'],
|
['/pargv/pargv.py', 'command', 'positional'],
|
||||||
{
|
{
|
||||||
'flag': True,
|
'flag': True,
|
||||||
'optional': ['value', 'test'],
|
'optional': ['value', 'test'],
|
||||||
'output_file': 'filename',
|
'output_file': ['filename'],
|
||||||
'f': True,
|
'f': True,
|
||||||
'l': True,
|
'l': True,
|
||||||
'g': ['name', 'name2'],
|
'g': ['name', 'name2'],
|
||||||
}
|
}
|
||||||
),))
|
),))
|
||||||
def test_all_parameters_at_once(argv, args, kwargs):
|
def test_all_parameters_at_once(argv, args, kwargs):
|
||||||
assert parse_args(argv) == (args, kwargs)
|
_args, _kwargs = parse_args(argv)
|
||||||
|
assert _args == args
|
||||||
|
assert _kwargs == kwargs
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
from pargv import parse_args
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def test_io():
|
|
||||||
for (argv, args, kwargs) in (
|
|
||||||
# Arguments
|
|
||||||
('name', ['name'], {}),
|
|
||||||
('name command', ['name', 'command'], {}),
|
|
||||||
# Hyphens
|
|
||||||
('a-b', ['a_b'], {}),
|
|
||||||
('---a', [], {'_a': True}),
|
|
||||||
('-a-', [], {'a': True, '_': True}),
|
|
||||||
# Options
|
|
||||||
('--option', [], {'option': True}),
|
|
||||||
('--option=2', [], {'option': '2'}),
|
|
||||||
('--option=2 4', [], {'option': ['2', '4']}),
|
|
||||||
('--option 2', [], {'option': '2'}),
|
|
||||||
('--option 2 4', [], {'option': ['2', '4']}),
|
|
||||||
# Short options
|
|
||||||
('-o', [], {'o': True}),
|
|
||||||
('-o=2', [], {'o': '2'}),
|
|
||||||
('-o=2 4', [], {'o': ['2', '4']}),
|
|
||||||
('-o 2', [], {'o': '2'}),
|
|
||||||
('-o 2 4', [], {'o': ['2', '4']}),
|
|
||||||
# Multiple short options
|
|
||||||
('-ox', [], {'o': True, 'x': True}),
|
|
||||||
('-ox=2', [], {'o': True, 'x': '2'}),
|
|
||||||
('-ox=2 4', [], {'o': True, 'x': ['2', '4']}),
|
|
||||||
('-ox 2', [], {'o': True, 'x': '2'}),
|
|
||||||
('-ox 2 4', [], {'o': True, 'x': ['2', '4']}),
|
|
||||||
):
|
|
||||||
assert parse_args(argv.split()) == (args, kwargs)
|
|
||||||
|
|
||||||
def test_empty_input():
|
|
||||||
for argv in (
|
|
||||||
'',
|
|
||||||
[],
|
|
||||||
{},
|
|
||||||
None,
|
|
||||||
False,
|
|
||||||
):
|
|
||||||
args, kwargs = parse_args(argv)
|
|
||||||
assert (len(args), len(kwargs)) == (1, 0)
|
|
||||||
|
|
||||||
def test_type_errors():
|
|
||||||
for argv in (
|
|
||||||
1,
|
|
||||||
True,
|
|
||||||
{'a': 1},
|
|
||||||
):
|
|
||||||
with pytest.raises(TypeError):
|
|
||||||
parse_args(argv)
|
|
||||||
|
|
||||||
def test_attribute_errors():
|
|
||||||
for argv in (
|
|
||||||
[1],
|
|
||||||
):
|
|
||||||
with pytest.raises(AttributeError):
|
|
||||||
parse_args(argv)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user