Compare commits
20 commits
2384d88336
...
6d01f9ffee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d01f9ffee | ||
|
|
52d96c2c51 | ||
|
|
15eb20ae11 | ||
|
|
c6f7dc8206 | ||
|
|
295d7f912e | ||
|
|
e61e064c41 | ||
|
|
6de205b260 | ||
|
|
694d9df04b | ||
|
|
e2951f1a21 | ||
|
|
195abb4299 | ||
|
|
285d7316be | ||
|
|
be4aba17dc | ||
|
|
3372a42524 | ||
|
|
b026f9755c | ||
|
|
ba1dc5d8c4 | ||
|
|
d963750cf1 | ||
|
|
7e8613e6fb | ||
|
|
4c528c0a17 | ||
|
|
82d8186062 | ||
|
|
2b3470af3b |
40 changed files with 939 additions and 1 deletions
5
AUTHORS
Normal file
5
AUTHORS
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
Authors
|
||||||
|
--------
|
||||||
|
|
||||||
|
Emmanuel Garette <gnunux@gnunux.info> lead developer
|
||||||
|
|
||||||
165
README.md
165
README.md
|
|
@ -1,3 +1,166 @@
|
||||||
# tiramisu-cmdline-parser
|
# tiramisu-cmdline-parser
|
||||||
|
|
||||||
Python3 parser for command-line options and arguments using Tiramisu engine.
|
Python3 parser for command-line options and arguments using Tiramisu engine.
|
||||||
|
|
||||||
|
# example
|
||||||
|
|
||||||
|
Let us start with a simple example
|
||||||
|
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from tiramisu_cmdline_parser import TiramisuCmdlineParser
|
||||||
|
from tiramisu import IntOption, StrOption, BoolOption, ChoiceOption, \
|
||||||
|
SymLinkOption, OptionDescription, Config
|
||||||
|
# build a Config with:
|
||||||
|
# * a choice for select a sub argument (str, list, int)
|
||||||
|
choiceoption = ChoiceOption('cmd',
|
||||||
|
'choice the sub argument',
|
||||||
|
('str', 'list', 'int'),
|
||||||
|
properties=('mandatory',
|
||||||
|
'positional'))
|
||||||
|
# * a boolean to pass script in verbosity mode with argument -v --verbosity
|
||||||
|
booloption = BoolOption('verbosity',
|
||||||
|
'increase output verbosity',
|
||||||
|
default=False)
|
||||||
|
short_booloption = SymLinkOption('v', booloption)
|
||||||
|
# * a string option if cmd is 'str'
|
||||||
|
str_ = StrOption('str',
|
||||||
|
'string option',
|
||||||
|
properties=('mandatory',),
|
||||||
|
requires=[{'option': choiceoption,
|
||||||
|
'expected': 'str',
|
||||||
|
'action': 'disabled',
|
||||||
|
'inverse': True}])
|
||||||
|
# * a list of strings option if cmd is 'list'
|
||||||
|
list_ = StrOption('list',
|
||||||
|
'list string option',
|
||||||
|
multi=True,
|
||||||
|
properties=('mandatory',),
|
||||||
|
requires=[{'option': choiceoption,
|
||||||
|
'expected': 'list',
|
||||||
|
'action': 'disabled',
|
||||||
|
'inverse': True}])
|
||||||
|
# * an integer option if cmd is 'int'
|
||||||
|
int_ = IntOption('int',
|
||||||
|
'int option',
|
||||||
|
properties=('mandatory',),
|
||||||
|
requires=[{'option': choiceoption,
|
||||||
|
'expected': 'int',
|
||||||
|
'action': 'disabled',
|
||||||
|
'inverse': True}])
|
||||||
|
# Now build Config
|
||||||
|
config = Config(OptionDescription('root',
|
||||||
|
'root',
|
||||||
|
[choiceoption,
|
||||||
|
booloption,
|
||||||
|
short_booloption,
|
||||||
|
str_,
|
||||||
|
list_,
|
||||||
|
int_
|
||||||
|
]))
|
||||||
|
# initialise the parser
|
||||||
|
config.property.read_write()
|
||||||
|
parser = TiramisuCmdlineParser(config)
|
||||||
|
# parse arguments of current script
|
||||||
|
parser.parse_args()
|
||||||
|
# now, print the result
|
||||||
|
print('result:')
|
||||||
|
config.property.read_only()
|
||||||
|
for key, value in config.value.dict().items():
|
||||||
|
print('- {} ({}): {}'.format(key,
|
||||||
|
config.option(key).option.doc(),
|
||||||
|
value))
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's print help:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py str -h
|
||||||
|
usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
|
||||||
|
{str,list,int}
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
{str,list,int} choice the sub argument
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-v, --verbosity increase output verbosity
|
||||||
|
--str STR string option
|
||||||
|
--list LIST [LIST ...]
|
||||||
|
list string option
|
||||||
|
--int INT int option
|
||||||
|
```
|
||||||
|
|
||||||
|
The positional argument 'cmd' is mandatory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py
|
||||||
|
usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
|
||||||
|
{str,list,int}
|
||||||
|
prog.py: error: the following arguments are required: cmd
|
||||||
|
```
|
||||||
|
|
||||||
|
If 'cmd' is 'str', --str become mandatory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py str
|
||||||
|
usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
|
||||||
|
{str,list,int}
|
||||||
|
prog.py: error: the following arguments are required: --str
|
||||||
|
```
|
||||||
|
|
||||||
|
If 'cmd' is 'str', cannot set --int argument:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py str --int 3
|
||||||
|
usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
|
||||||
|
{str,list,int}
|
||||||
|
prog.py: error: unrecognized arguments: --int
|
||||||
|
```
|
||||||
|
|
||||||
|
With all mandatories arguments:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py str --str value
|
||||||
|
result:
|
||||||
|
- cmd (choice the sub argument): str
|
||||||
|
- verbosity (increase output verbosity): False
|
||||||
|
- v (increase output verbosity): False
|
||||||
|
- str (string option): value
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py int --int 3
|
||||||
|
result:
|
||||||
|
- cmd (choice the sub argument): int
|
||||||
|
- verbosity (increase output verbosity): False
|
||||||
|
- v (increase output verbosity): False
|
||||||
|
- int (int option): 3
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py list --list a b c
|
||||||
|
result:
|
||||||
|
- cmd (choice the sub argument): list
|
||||||
|
- verbosity (increase output verbosity): False
|
||||||
|
- v (increase output verbosity): False
|
||||||
|
- list (list string option): ['a', 'b', 'c']
|
||||||
|
```
|
||||||
|
|
||||||
|
Add --verbosity argument:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py list --list a b c -v
|
||||||
|
result:
|
||||||
|
- cmd (choice the sub argument): list
|
||||||
|
- verbosity (increase output verbosity): True
|
||||||
|
- v (increase output verbosity): True
|
||||||
|
- list (list string option): ['a', 'b', 'c']
|
||||||
|
[gnunux@localhost tiramisu-parser]$ python3 prog.py list --list a b c --verbosity
|
||||||
|
result:
|
||||||
|
- cmd (choice the sub argument): list
|
||||||
|
- verbosity (increase output verbosity): True
|
||||||
|
- v (increase output verbosity): True
|
||||||
|
- list (list string option): ['a', 'b', 'c']
|
||||||
|
```
|
||||||
|
|
|
||||||
178
examples/Hangman/example.py
Normal file
178
examples/Hangman/example.py
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Hangman example
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from random import choice
|
||||||
|
import unicodedata
|
||||||
|
import re
|
||||||
|
from os import unlink
|
||||||
|
from os.path import isfile
|
||||||
|
from tiramisu import RegexpOption, OptionDescription, Config, IntOption, UnicodeOption, BoolOption, ParamOption, Params
|
||||||
|
from tiramisu.storage import storage_type
|
||||||
|
from tiramisu.storage.sqlite3.storage import SETTING
|
||||||
|
from tiramisu_cmdline_parser import TiramisuCmdlineParser
|
||||||
|
|
||||||
|
|
||||||
|
LANG = 'fr_FR'
|
||||||
|
DICT_FILE = '/usr/share/myspell/{}.dic'.format(LANG)
|
||||||
|
WORD_REGEXP = re.compile(r'^[a-z]{7,12}$')
|
||||||
|
PROPOSALS_LEN = 27
|
||||||
|
NB_PROPOSALS = 6
|
||||||
|
|
||||||
|
|
||||||
|
def remove_accent(word):
|
||||||
|
"""remove all accent"""
|
||||||
|
word = unicodedata.normalize('NFD', word)
|
||||||
|
return word.encode('ascii', 'ignore').decode()
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_word():
|
||||||
|
"""get line randomly in myspell file
|
||||||
|
"""
|
||||||
|
with open(DICT_FILE, 'r') as file_content:
|
||||||
|
word = choice(file_content.readlines()).strip()
|
||||||
|
if word.endswith('/S.'):
|
||||||
|
word = word[:-3]
|
||||||
|
if word.endswith('/X.'):
|
||||||
|
word = word[:-3]
|
||||||
|
if word.endswith('/F.'):
|
||||||
|
word = word[:-3]
|
||||||
|
if word.endswith('/a0p+') or word.endswith('/d0p+') or word.endswith('/a3p+'):
|
||||||
|
word = word[:-5]
|
||||||
|
if not WORD_REGEXP.search(remove_accent(word)):
|
||||||
|
return get_random_word()
|
||||||
|
return word
|
||||||
|
|
||||||
|
|
||||||
|
def display_uncomplete_word(word, *proposals):
|
||||||
|
"""display response with proposals
|
||||||
|
"""
|
||||||
|
if display_proposals_left(display_misses(word, *proposals)) == 0:
|
||||||
|
return word
|
||||||
|
display = ['-'] * len(word)
|
||||||
|
for idx, char in enumerate(remove_accent(word)):
|
||||||
|
if char in proposals:
|
||||||
|
display[idx] = word[idx]
|
||||||
|
return ''.join(display)
|
||||||
|
|
||||||
|
|
||||||
|
def display_misses(word, *proposals):
|
||||||
|
"""display all proposals
|
||||||
|
"""
|
||||||
|
ret = list(set(proposals) - set(list(remove_accent(word))))
|
||||||
|
if None in ret:
|
||||||
|
ret.remove(None)
|
||||||
|
ret.sort()
|
||||||
|
return ' '.join(ret)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_misses(misses):
|
||||||
|
if display_proposals_left(misses) == 0:
|
||||||
|
raise ValueError('No more guest possible')
|
||||||
|
|
||||||
|
|
||||||
|
def display_proposals_left(misses):
|
||||||
|
if not misses:
|
||||||
|
return NB_PROPOSALS
|
||||||
|
return max(NB_PROPOSALS - len(misses.split(' ')), 0)
|
||||||
|
|
||||||
|
|
||||||
|
def display_proposal(word, *proposals):
|
||||||
|
if display_uncomplete_word(word, *proposals) == word:
|
||||||
|
return False
|
||||||
|
return display_proposals_left(display_misses(word, *proposals)) != 0
|
||||||
|
|
||||||
|
|
||||||
|
class ProposalOption(RegexpOption):
|
||||||
|
__slots__ = tuple()
|
||||||
|
_regexp = re.compile(r'^[a-z]$')
|
||||||
|
_display_name = 'proposal'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
options = []
|
||||||
|
proposal = None
|
||||||
|
word = UnicodeOption('word',
|
||||||
|
'Word',
|
||||||
|
properties=('hidden', 'force_store_value'),
|
||||||
|
callback=get_random_word)
|
||||||
|
proposals = [ParamOption(word)]
|
||||||
|
for idx in range(PROPOSALS_LEN):
|
||||||
|
requires = [{'option': 'self',
|
||||||
|
'expected': None,
|
||||||
|
'action': 'hidden',
|
||||||
|
'inverse': True}]
|
||||||
|
if proposal is not None:
|
||||||
|
display = BoolOption('display{}'.format(idx),
|
||||||
|
'Display {}'.format(idx),
|
||||||
|
properties=('hidden',),
|
||||||
|
callback=display_proposal,
|
||||||
|
callback_params=Params(tuple(proposals)))
|
||||||
|
options.append(display)
|
||||||
|
requires.append({'option': proposal,
|
||||||
|
'expected': None,
|
||||||
|
'action': 'disabled'})
|
||||||
|
requires.append({'option': display,
|
||||||
|
'expected': False,
|
||||||
|
'action': 'disabled'})
|
||||||
|
|
||||||
|
proposal = ProposalOption('guess{}'.format(idx),
|
||||||
|
'Guess {}'.format(idx),
|
||||||
|
requires=requires,
|
||||||
|
properties=('positional',))
|
||||||
|
#FIXME maximum recursion ...
|
||||||
|
#if proposals:
|
||||||
|
# proposal.impl_add_consistency('not_equal', proposals[0])
|
||||||
|
|
||||||
|
proposals.append(ParamOption(proposal, True))
|
||||||
|
options.append(proposal)
|
||||||
|
#
|
||||||
|
proposal_word = UnicodeOption('proposal_word',
|
||||||
|
'Word',
|
||||||
|
properties=('frozen',),
|
||||||
|
callback=display_uncomplete_word,
|
||||||
|
callback_params=Params(tuple(proposals)))
|
||||||
|
misses = UnicodeOption('misses',
|
||||||
|
'Misses',
|
||||||
|
properties=('frozen',),
|
||||||
|
callback=display_misses,
|
||||||
|
callback_params=Params(tuple(proposals)),
|
||||||
|
validator=validate_misses)
|
||||||
|
proposals_left = IntOption('proposals_left',
|
||||||
|
'Proposals left',
|
||||||
|
properties=('frozen',),
|
||||||
|
callback=display_proposals_left,
|
||||||
|
callback_params=Params(ParamOption(misses)))
|
||||||
|
#descr = OptionDescription('proposals',
|
||||||
|
# 'Suggesting letters',
|
||||||
|
# options)
|
||||||
|
storage_type.set('sqlite3')
|
||||||
|
config = Config(OptionDescription('root', 'root', [word, proposal_word, misses, proposals_left] + options), persistent=True, session_id='hangman')
|
||||||
|
parser = TiramisuCmdlineParser(config)
|
||||||
|
try:
|
||||||
|
parser.parse_args()
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
config = parser.get_config()
|
||||||
|
filename = '{}/tiramisu.db'.format(SETTING.dir_database)
|
||||||
|
lost = False
|
||||||
|
for name in ['proposal_word', 'misses', 'proposals_left']:
|
||||||
|
option = config.option(name)
|
||||||
|
try:
|
||||||
|
value = option.value.get()
|
||||||
|
print('{}: {}'.format(option.option.doc(), value))
|
||||||
|
except ValueError as err:
|
||||||
|
lost = True
|
||||||
|
err.prefix = ''
|
||||||
|
print(option.option.doc(), str(err))
|
||||||
|
if isfile(filename):
|
||||||
|
unlink(filename)
|
||||||
|
if not lost and \
|
||||||
|
config.option('proposal_word').value.get() == config.forcepermissive.option('word').value.get():
|
||||||
|
print('You win')
|
||||||
|
if isfile(filename):
|
||||||
|
unlink(filename)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
32
examples/remote/example.py
Normal file
32
examples/remote/example.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Hangman example
|
||||||
|
"""
|
||||||
|
from json import loads, dumps
|
||||||
|
from urllib.request import urlopen, Request
|
||||||
|
from tiramisu_json_api import Config
|
||||||
|
from tiramisu_cmdline_parser import TiramisuCmdlineParser
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteConfig(Config):
|
||||||
|
def __init__(self,
|
||||||
|
url):
|
||||||
|
json = loads(urlopen(url).read())
|
||||||
|
super().__init__(json)
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
def send_data(self,
|
||||||
|
updates):
|
||||||
|
request = Request(self.url, dumps(updates).encode(), method='POST')
|
||||||
|
return loads(urlopen(request).read())
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
config = RemoteConfig('http://localhost:8000')
|
||||||
|
parser = TiramisuCmdlineParser(config)
|
||||||
|
parser.parse_args()
|
||||||
|
config = parser.get_config()
|
||||||
|
print(config.value.dict())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
29
setup.py
Normal file
29
setup.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
import tiramisu_cmdline_parser
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='tiramisu_cmdline_parser',
|
||||||
|
version=tiramisu_cmdline_parser.__version__,
|
||||||
|
packages=find_packages(),
|
||||||
|
author="Emmanuel Garette & Tiramisu Team",
|
||||||
|
description="command-line parser using Tiramisu.",
|
||||||
|
long_description="""
|
||||||
|
Python3 parser for command-line options and arguments using Tiramisu engine.
|
||||||
|
""",
|
||||||
|
include_package_data=True,
|
||||||
|
url='https://framagit.org/tiramisu/tiramisu-cmdline-parser',
|
||||||
|
|
||||||
|
classifiers=[
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Development Status :: 1 - Planning",
|
||||||
|
"License :: LGPLv3",
|
||||||
|
"Natural Language :: French",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Topic :: Communications",
|
||||||
|
],
|
||||||
|
)
|
||||||
1
test/data/compare/10_positional/argparse.py
Normal file
1
test/data/compare/10_positional/argparse.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_argument("echo", help="echo the string you use here")
|
||||||
1
test/data/compare/10_positional/tiramisu.py
Normal file
1
test/data/compare/10_positional/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(StrOption('echo', 'echo the string you use here', properties=('mandatory', 'positional')))
|
||||||
1
test/data/compare/10_positional_default/argparse.py
Normal file
1
test/data/compare/10_positional_default/argparse.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_argument("echo", help="echo the string you use here", default='blah', nargs='?')
|
||||||
1
test/data/compare/10_positional_default/tiramisu.py
Normal file
1
test/data/compare/10_positional_default/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(StrOption('echo', 'echo the string you use here', properties=('mandatory', 'positional'), default='blah'))
|
||||||
2
test/data/compare/10_positional_int/argparse.py
Normal file
2
test/data/compare/10_positional_int/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument("square", help="display a square of a given number",
|
||||||
|
type=int)
|
||||||
1
test/data/compare/10_positional_int/tiramisu.py
Normal file
1
test/data/compare/10_positional_int/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(IntOption('square', 'display a square of a given number', properties=('mandatory', 'positional')))
|
||||||
1
test/data/compare/10_positional_list/argparse.py
Normal file
1
test/data/compare/10_positional_list/argparse.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_argument("echo", help="echo the string you use here", nargs='+')
|
||||||
1
test/data/compare/10_positional_list/tiramisu.py
Normal file
1
test/data/compare/10_positional_list/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(StrOption('echo', 'echo the string you use here', properties=('mandatory', 'positional'), multi=True))
|
||||||
1
test/data/compare/20_bool/argparse.py
Normal file
1
test/data/compare/20_bool/argparse.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_argument('--verbosity', help='increase output verbosity', action='store_true')
|
||||||
1
test/data/compare/20_bool/tiramisu.py
Normal file
1
test/data/compare/20_bool/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(BoolOption('verbosity', 'increase output verbosity', default=False))
|
||||||
1
test/data/compare/20_bool_true/argparse.py
Normal file
1
test/data/compare/20_bool_true/argparse.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_argument('--verbosity', help='increase output verbosity', action='store_false')
|
||||||
1
test/data/compare/20_bool_true/tiramisu.py
Normal file
1
test/data/compare/20_bool_true/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(BoolOption('verbosity', 'increase output verbosity', default=True))
|
||||||
2
test/data/compare/20_choice/argparse.py
Normal file
2
test/data/compare/20_choice/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('--door', help='Door numbers', choices=['1', '2', '3'])
|
||||||
|
|
||||||
1
test/data/compare/20_choice/tiramisu.py
Normal file
1
test/data/compare/20_choice/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(ChoiceOption('door', 'Door numbers', ('1', '2', '3')))
|
||||||
2
test/data/compare/20_int/argparse.py
Normal file
2
test/data/compare/20_int/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('--int', help='integer', type=int)
|
||||||
|
|
||||||
1
test/data/compare/20_int/tiramisu.py
Normal file
1
test/data/compare/20_int/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(IntOption('int', 'integer'))
|
||||||
2
test/data/compare/20_string/argparse.py
Normal file
2
test/data/compare/20_string/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('--foo', help='foo help')
|
||||||
|
|
||||||
2
test/data/compare/20_string/tiramisu.py
Normal file
2
test/data/compare/20_string/tiramisu.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_arguments(StrOption('foo', 'foo help'))
|
||||||
|
|
||||||
2
test/data/compare/20_string_list/argparse.py
Normal file
2
test/data/compare/20_string_list/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('--foo', help='foo help', nargs='*')
|
||||||
|
|
||||||
2
test/data/compare/20_string_list/tiramisu.py
Normal file
2
test/data/compare/20_string_list/tiramisu.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_arguments(StrOption('foo', 'foo help', multi=True))
|
||||||
|
|
||||||
2
test/data/compare/30_choice_int/argparse.py
Normal file
2
test/data/compare/30_choice_int/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('--door', help='Door numbers', choices=[1, 2, 3])
|
||||||
|
|
||||||
1
test/data/compare/30_choice_int/tiramisu.py
Normal file
1
test/data/compare/30_choice_int/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments(ChoiceOption('door', 'Door numbers', (1, 2, 3)))
|
||||||
2
test/data/compare/30_string_default/argparse.py
Normal file
2
test/data/compare/30_string_default/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('--foo', help='foo help', default='default', nargs='?')
|
||||||
|
|
||||||
2
test/data/compare/30_string_default/tiramisu.py
Normal file
2
test/data/compare/30_string_default/tiramisu.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_arguments(StrOption('foo', 'foo help', 'default'))
|
||||||
|
|
||||||
1
test/data/compare/30_string_short/argparse.py
Normal file
1
test/data/compare/30_string_short/argparse.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_argument('-f', '--foo', help='foo help')
|
||||||
3
test/data/compare/30_string_short/tiramisu.py
Normal file
3
test/data/compare/30_string_short/tiramisu.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
str_long = StrOption('foo', 'foo help')
|
||||||
|
str_short = SymLinkOption('f', str_long)
|
||||||
|
parser.add_arguments([str_long, str_short])
|
||||||
2
test/data/compare/40_multi_bool/argparse.py
Normal file
2
test/data/compare/40_multi_bool/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('-v', help='increase output verbosity', action='store_true')
|
||||||
|
parser.add_argument('-s', help='second argument', action='store_true')
|
||||||
1
test/data/compare/40_multi_bool/tiramisu.py
Normal file
1
test/data/compare/40_multi_bool/tiramisu.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
parser.add_arguments([BoolOption('v', 'increase output verbosity', default=False), BoolOption('s', 'second argument', default=False)])
|
||||||
3
test/data/compare/40_positional_optional/argparse.py
Normal file
3
test/data/compare/40_positional_optional/argparse.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
parser.add_argument("echo", help="echo the string you use here")
|
||||||
|
parser.add_argument('--verbosity', help='increase output verbosity', action='store_true')
|
||||||
|
|
||||||
3
test/data/compare/40_positional_optional/tiramisu.py
Normal file
3
test/data/compare/40_positional_optional/tiramisu.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
parser.add_arguments([StrOption('echo', 'echo the string you use here', properties=('mandatory', 'positional')),
|
||||||
|
BoolOption('verbosity', 'increase output verbosity', default=False)])
|
||||||
|
|
||||||
2
test/data/compare/40_short_long/argparse.py
Normal file
2
test/data/compare/40_short_long/argparse.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
parser.add_argument('-v', help='increase output verbosity', action='store_true')
|
||||||
|
parser.add_argument('-i', '--int', help='integer', type=int)
|
||||||
4
test/data/compare/40_short_long/tiramisu.py
Normal file
4
test/data/compare/40_short_long/tiramisu.py
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
int_long = IntOption('int', 'integer')
|
||||||
|
parser.add_arguments([BoolOption('v', 'increase output verbosity', default=False),
|
||||||
|
int_long,
|
||||||
|
SymLinkOption('i', int_long)])
|
||||||
193
test/test_readme.py
Normal file
193
test/test_readme.py
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
from io import StringIO
|
||||||
|
from contextlib import redirect_stdout, redirect_stderr
|
||||||
|
|
||||||
|
|
||||||
|
from tiramisu_cmdline_parser import TiramisuCmdlineParser
|
||||||
|
from tiramisu import IntOption, StrOption, BoolOption, ChoiceOption, \
|
||||||
|
SymLinkOption, OptionDescription, Config
|
||||||
|
|
||||||
|
|
||||||
|
def get_config():
|
||||||
|
choiceoption = ChoiceOption('cmd',
|
||||||
|
'choice the sub argument',
|
||||||
|
('str', 'list', 'int', 'none'),
|
||||||
|
properties=('mandatory',
|
||||||
|
'positional'))
|
||||||
|
booloption = BoolOption('verbosity',
|
||||||
|
'increase output verbosity',
|
||||||
|
default=False)
|
||||||
|
short_booloption = SymLinkOption('v', booloption)
|
||||||
|
str_ = StrOption('str',
|
||||||
|
'string option',
|
||||||
|
properties=('mandatory',),
|
||||||
|
requires=[{'option': choiceoption,
|
||||||
|
'expected': 'str',
|
||||||
|
'action': 'disabled',
|
||||||
|
'inverse': True}])
|
||||||
|
list_ = StrOption('list',
|
||||||
|
'list string option',
|
||||||
|
multi=True,
|
||||||
|
properties=('mandatory',),
|
||||||
|
requires=[{'option': choiceoption,
|
||||||
|
'expected': 'list',
|
||||||
|
'action': 'disabled',
|
||||||
|
'inverse': True}])
|
||||||
|
int_ = IntOption('int',
|
||||||
|
'int option',
|
||||||
|
properties=('mandatory',),
|
||||||
|
requires=[{'option': choiceoption,
|
||||||
|
'expected': 'int',
|
||||||
|
'action': 'disabled',
|
||||||
|
'inverse': True}])
|
||||||
|
config = Config(OptionDescription('root',
|
||||||
|
'root',
|
||||||
|
[choiceoption,
|
||||||
|
booloption,
|
||||||
|
short_booloption,
|
||||||
|
str_,
|
||||||
|
list_,
|
||||||
|
int_
|
||||||
|
]))
|
||||||
|
config.property.read_write()
|
||||||
|
return config
|
||||||
|
|
||||||
|
def test_readme_help():
|
||||||
|
output = """usage: prog.py [-h] [-v] {str,list,int,none}
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
{str,list,int,none} choice the sub argument
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-v, --verbosity increase output verbosity
|
||||||
|
"""
|
||||||
|
parser = TiramisuCmdlineParser(get_config(), 'prog.py')
|
||||||
|
f = StringIO()
|
||||||
|
with redirect_stdout(f):
|
||||||
|
parser.print_help()
|
||||||
|
assert f.getvalue() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_positional_mandatory():
|
||||||
|
output = """usage: prog.py [-h] [-v] {str,list,int,none}
|
||||||
|
prog.py: error: the following arguments are required: cmd
|
||||||
|
"""
|
||||||
|
parser = TiramisuCmdlineParser(get_config(), 'prog.py')
|
||||||
|
f = StringIO()
|
||||||
|
with redirect_stderr(f):
|
||||||
|
try:
|
||||||
|
parser.parse_args([])
|
||||||
|
except SystemExit as err:
|
||||||
|
assert str(err) == "2"
|
||||||
|
else:
|
||||||
|
raise Exception('must raises')
|
||||||
|
assert f.getvalue() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_mandatory():
|
||||||
|
output = """usage: prog.py [-h] [-v] --str STR {str,list,int,none}
|
||||||
|
prog.py: error: the following arguments are required: --str
|
||||||
|
"""
|
||||||
|
parser = TiramisuCmdlineParser(get_config(), 'prog.py')
|
||||||
|
f = StringIO()
|
||||||
|
with redirect_stderr(f):
|
||||||
|
try:
|
||||||
|
parser.parse_args(['str'])
|
||||||
|
except SystemExit as err:
|
||||||
|
assert str(err) == "2"
|
||||||
|
else:
|
||||||
|
raise Exception('must raises')
|
||||||
|
assert f.getvalue() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_cross():
|
||||||
|
output = """usage: prog.py [-h] [-v] {str,list,int,none}
|
||||||
|
prog.py: error: unrecognized arguments: --int
|
||||||
|
"""
|
||||||
|
parser = TiramisuCmdlineParser(get_config(), 'prog.py')
|
||||||
|
f = StringIO()
|
||||||
|
with redirect_stderr(f):
|
||||||
|
try:
|
||||||
|
parser.parse_args(['none', '--int'])
|
||||||
|
except SystemExit as err:
|
||||||
|
assert str(err) == "2"
|
||||||
|
else:
|
||||||
|
raise Exception('must raises')
|
||||||
|
assert f.getvalue() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_int():
|
||||||
|
output = {'cmd': 'int',
|
||||||
|
'int': 3,
|
||||||
|
'verbosity': False,
|
||||||
|
'v': False}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['int', '--int', '3'])
|
||||||
|
# assert config.value.dict() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_int_verbosity():
|
||||||
|
output = {'cmd': 'int',
|
||||||
|
'int': 3,
|
||||||
|
'verbosity': True,
|
||||||
|
'v': True}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['int', '--int', '3', '--verbosity'])
|
||||||
|
assert config.value.dict() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_int_verbosity_short():
|
||||||
|
output = {'cmd': 'int',
|
||||||
|
'int': 3,
|
||||||
|
'verbosity': True,
|
||||||
|
'v': True}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['int', '--int', '3', '-v'])
|
||||||
|
assert config.value.dict() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_str():
|
||||||
|
output = {'cmd': 'str',
|
||||||
|
'str': 'value',
|
||||||
|
'verbosity': False,
|
||||||
|
'v': False}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['str', '--str', 'value'])
|
||||||
|
assert config.value.dict() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_str_int():
|
||||||
|
output = {'cmd': 'str',
|
||||||
|
'str': '3',
|
||||||
|
'verbosity': False,
|
||||||
|
'v': False}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['str', '--str', '3'])
|
||||||
|
assert config.value.dict() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_list():
|
||||||
|
output = {'cmd': 'list',
|
||||||
|
'list': ['a', 'b', 'c'],
|
||||||
|
'verbosity': False,
|
||||||
|
'v': False}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['list', '--list', 'a', 'b', 'c'])
|
||||||
|
assert config.value.dict() == output
|
||||||
|
|
||||||
|
|
||||||
|
def test_readme_list_uniq():
|
||||||
|
output = {'cmd': 'list',
|
||||||
|
'list': ['a'],
|
||||||
|
'verbosity': False,
|
||||||
|
'v': False}
|
||||||
|
config = get_config()
|
||||||
|
parser = TiramisuCmdlineParser(config, 'prog.py')
|
||||||
|
parser.parse_args(['list', '--list', 'a'])
|
||||||
|
assert config.value.dict() == output
|
||||||
4
tiramisu_cmdline_parser/__init__.py
Normal file
4
tiramisu_cmdline_parser/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
from .tiramisu_cmdline_parser import TiramisuCmdlineParser
|
||||||
|
|
||||||
|
__version__ = "0.0.1"
|
||||||
|
__all__ = ('TiramisuCmdlineParser',)
|
||||||
281
tiramisu_cmdline_parser/tiramisu_cmdline_parser.py
Normal file
281
tiramisu_cmdline_parser/tiramisu_cmdline_parser.py
Normal file
|
|
@ -0,0 +1,281 @@
|
||||||
|
# Copyright (C) 2018 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from typing import Union, List, Optional
|
||||||
|
from argparse import ArgumentParser, Namespace, SUPPRESS, _HelpAction
|
||||||
|
try:
|
||||||
|
from tiramisu import Config
|
||||||
|
from tiramisu.error import PropertiesOptionError
|
||||||
|
except ImportError:
|
||||||
|
Config = None
|
||||||
|
from tiramisu_json_api.error import PropertiesOptionError
|
||||||
|
try:
|
||||||
|
from tiramisu_json_api import Config as ConfigJson
|
||||||
|
if Config is None:
|
||||||
|
Config = ConfigJson
|
||||||
|
except ImportError:
|
||||||
|
ConfigJson = Config
|
||||||
|
|
||||||
|
|
||||||
|
class TiramisuNamespace(Namespace):
|
||||||
|
def _populate(self):
|
||||||
|
#self._config.property.read_only()
|
||||||
|
for tiramisu_key, tiramisu_value in self._config.value.dict().items():
|
||||||
|
option = self._config.option(tiramisu_key)
|
||||||
|
if not option.option.issymlinkoption():
|
||||||
|
if tiramisu_value == [] and option.option.ismulti() and option.owner.isdefault():
|
||||||
|
tiramisu_value = None
|
||||||
|
super().__setattr__(tiramisu_key, tiramisu_value)
|
||||||
|
#self._config.property.read_write()
|
||||||
|
|
||||||
|
def __init__(self, config):
|
||||||
|
self._config = config
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def __setattr__(self, key, value):
|
||||||
|
if key == '_config':
|
||||||
|
super().__setattr__(key, value)
|
||||||
|
return
|
||||||
|
# self._config.property.read_write()
|
||||||
|
option = self._config.option(key)
|
||||||
|
if option.option.ismulti() and value is not None and not isinstance(value, list):
|
||||||
|
value = [value]
|
||||||
|
option.value.set(value)
|
||||||
|
|
||||||
|
def __getattribute__(self, key):
|
||||||
|
if key == '__dict__' and hasattr(self, '_config'):
|
||||||
|
self._populate()
|
||||||
|
return super().__getattribute__(key)
|
||||||
|
|
||||||
|
|
||||||
|
class _TiramisuHelpAction(_HelpAction):
|
||||||
|
needs = False
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
_TiramisuHelpAction.needs = True
|
||||||
|
|
||||||
|
def display(self, parser):
|
||||||
|
_HelpAction.__call__(self, parser, None, None)
|
||||||
|
|
||||||
|
|
||||||
|
class TiramisuCmdlineParser(ArgumentParser):
|
||||||
|
def __init__(self,
|
||||||
|
config: Union[Config, ConfigJson],
|
||||||
|
*args,
|
||||||
|
fullpath: bool=True,
|
||||||
|
_forhelp: bool=False,
|
||||||
|
**kwargs):
|
||||||
|
self.fullpath = fullpath
|
||||||
|
self.config = config
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.register('action', 'help', _TiramisuHelpAction)
|
||||||
|
self._config_to_argparser(_forhelp,
|
||||||
|
self.config.option)
|
||||||
|
|
||||||
|
def _pop_action_class(self, kwargs, default=None):
|
||||||
|
ret = super()._pop_action_class(kwargs, default)
|
||||||
|
if kwargs.get('action') != 'help' and kwargs.get('dest') != 'help':
|
||||||
|
return ret
|
||||||
|
return _TiramisuHelpAction
|
||||||
|
|
||||||
|
def _match_arguments_partial(self,
|
||||||
|
actions,
|
||||||
|
arg_string_pattern):
|
||||||
|
# used only when check first proposal for first value
|
||||||
|
# we have to remove all actions with propertieserror
|
||||||
|
# so only first settable option will be returned
|
||||||
|
actions_pop = []
|
||||||
|
for idx, action in enumerate(actions):
|
||||||
|
if self.config.option(action.dest).property.get(only_raises=True):
|
||||||
|
actions_pop.append(idx)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
for idx in actions_pop:
|
||||||
|
actions.pop(0)
|
||||||
|
return super()._match_arguments_partial(actions, arg_string_pattern)
|
||||||
|
|
||||||
|
def _parse_known_args(self, args=None, namespace=None):
|
||||||
|
|
||||||
|
namespace_, args_ = super()._parse_known_args(args, namespace)
|
||||||
|
if args != args_ and args_ and args_[0].startswith(self.prefix_chars):
|
||||||
|
# option that was disabled are no more disable
|
||||||
|
# so create a new parser
|
||||||
|
new_parser = TiramisuCmdlineParser(self.config,
|
||||||
|
self.prog,
|
||||||
|
fullpath=self.fullpath)
|
||||||
|
namespace_, args_ = new_parser._parse_known_args(args_, namespace)
|
||||||
|
else:
|
||||||
|
if self._registries['action']['help'].needs:
|
||||||
|
# display help only when all variables assignemnt are done
|
||||||
|
self._registries['action']['help'].needs = False
|
||||||
|
helper = self._registries['action']['help'](None)
|
||||||
|
helper.display(self)
|
||||||
|
return namespace_, args_
|
||||||
|
|
||||||
|
def add_argument(self, *args, **kwargs):
|
||||||
|
if args == ('-h', '--help'):
|
||||||
|
super().add_argument(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('do not use add_argument')
|
||||||
|
|
||||||
|
def add_arguments(self, *args, **kwargs):
|
||||||
|
raise NotImplementedError('do not use add_argument')
|
||||||
|
|
||||||
|
def add_subparsers(self, *args, **kwargs):
|
||||||
|
raise NotImplementedError('do not use add_subparsers')
|
||||||
|
|
||||||
|
def _gen_argument(self, name, properties):
|
||||||
|
if len(name) == 1 and 'longargument' not in properties:
|
||||||
|
return self.prefix_chars + name
|
||||||
|
return self.prefix_chars * 2 + name
|
||||||
|
|
||||||
|
def _config_to_argparser(self,
|
||||||
|
_forhelp: bool,
|
||||||
|
config,
|
||||||
|
prefix: Optional[str]=None,
|
||||||
|
group=None) -> None:
|
||||||
|
if group is None:
|
||||||
|
group = super()
|
||||||
|
actions = {}
|
||||||
|
for obj in config.list(type='all'):
|
||||||
|
option = obj.option
|
||||||
|
if option.isoptiondescription():
|
||||||
|
if _forhelp:
|
||||||
|
group = self.add_argument_group(option.doc())
|
||||||
|
if prefix:
|
||||||
|
prefix_ = prefix + '.' + option.name()
|
||||||
|
else:
|
||||||
|
prefix_ = option.path()
|
||||||
|
self._config_to_argparser(_forhelp, obj, prefix_, group)
|
||||||
|
continue
|
||||||
|
if 'frozen' in option.properties():
|
||||||
|
continue
|
||||||
|
name = option.name()
|
||||||
|
if name.startswith(self.prefix_chars):
|
||||||
|
raise ValueError('name cannot startswith "{}"'.format(self.prefix_chars))
|
||||||
|
if self.fullpath and prefix:
|
||||||
|
name = prefix + '.' + name
|
||||||
|
properties = obj.property.get()
|
||||||
|
kwargs = {'help': option.doc().replace('%', '%%')}
|
||||||
|
if option.issymlinkoption():
|
||||||
|
actions[option.name(follow_symlink=True)][0].insert(0, self._gen_argument(name, properties))
|
||||||
|
continue
|
||||||
|
if 'positional' in properties:
|
||||||
|
if not 'mandatory' in properties:
|
||||||
|
raise ValueError('"positional" argument must be "mandatory" too')
|
||||||
|
args = [option.path()]
|
||||||
|
if _forhelp:
|
||||||
|
kwargs['default'] = obj.value.default()
|
||||||
|
else:
|
||||||
|
kwargs['default'] = obj.value.get()
|
||||||
|
kwargs['nargs'] = '?'
|
||||||
|
else:
|
||||||
|
kwargs['dest'] = option.path()
|
||||||
|
kwargs['default'] = SUPPRESS
|
||||||
|
args = [self._gen_argument(name, properties)]
|
||||||
|
if _forhelp and 'mandatory' in properties:
|
||||||
|
kwargs['required'] = True
|
||||||
|
if option.type() == 'boolean':
|
||||||
|
if 'mandatory' in properties:
|
||||||
|
raise ValueError('"mandatory" property is not allowed for BoolOption')
|
||||||
|
#if not isinstance(option.default(), bool):
|
||||||
|
# raise ValueError('default value is mandatory for BoolOption')
|
||||||
|
if obj.value.get() is False:
|
||||||
|
action = 'store_true'
|
||||||
|
else:
|
||||||
|
action = 'store_false'
|
||||||
|
kwargs['action'] = action
|
||||||
|
else:
|
||||||
|
if _forhelp:
|
||||||
|
value = obj.value.default()
|
||||||
|
else:
|
||||||
|
value = obj.value.get()
|
||||||
|
if value not in [None, []]:
|
||||||
|
#kwargs['default'] = kwargs['const'] = option.default()
|
||||||
|
#kwargs['action'] = 'store_const'
|
||||||
|
kwargs['nargs'] = '?'
|
||||||
|
if option.ismulti():
|
||||||
|
if _forhelp and 'mandatory' in properties:
|
||||||
|
kwargs['nargs'] = '+'
|
||||||
|
else:
|
||||||
|
kwargs['nargs'] = '*'
|
||||||
|
if option.type() == 'string':
|
||||||
|
pass
|
||||||
|
elif option.type() == 'integer':
|
||||||
|
kwargs['type'] = int
|
||||||
|
elif option.type() == 'choice':
|
||||||
|
kwargs['choices'] = obj.value.list()
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
#raise NotImplementedError('not supported yet')
|
||||||
|
actions[option.name()] = (args, kwargs)
|
||||||
|
for args, kwargs in actions.values():
|
||||||
|
group.add_argument(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args(self,
|
||||||
|
*args,
|
||||||
|
valid_mandatory=True,
|
||||||
|
**kwargs):
|
||||||
|
kwargs['namespace'] = TiramisuNamespace(self.config)
|
||||||
|
try:
|
||||||
|
namespaces = super().parse_args(*args, **kwargs)
|
||||||
|
del namespaces.__dict__['_config']
|
||||||
|
except PropertiesOptionError as err:
|
||||||
|
name = err._option_bag.option.impl_getname()
|
||||||
|
properties = self.config.option(name).property.get()
|
||||||
|
if 'positional' not in properties:
|
||||||
|
if len(name) == 1 and 'longargument' not in properties:
|
||||||
|
name = self.prefix_chars + name
|
||||||
|
else:
|
||||||
|
name = self.prefix_chars * 2 + name
|
||||||
|
if err.proptype == ['mandatory']:
|
||||||
|
self.error('the following arguments are required: {}'.format(name))
|
||||||
|
else:
|
||||||
|
self.error('unrecognized arguments: {}'.format(name))
|
||||||
|
if valid_mandatory:
|
||||||
|
for key in self.config.value.mandatory():
|
||||||
|
properties = self.config.option(key).property.get()
|
||||||
|
if 'positional' not in properties:
|
||||||
|
if self.fullpath or '.' not in key:
|
||||||
|
name = key
|
||||||
|
else:
|
||||||
|
name = key.rsplit('.', 1)[1]
|
||||||
|
args = self._gen_argument(name, self.config.option(key).property.get())
|
||||||
|
else:
|
||||||
|
args = key
|
||||||
|
self.error('the following arguments are required: {}'.format(args))
|
||||||
|
return namespaces
|
||||||
|
|
||||||
|
def format_usage(self,
|
||||||
|
*args,
|
||||||
|
**kwargs):
|
||||||
|
help_formatter = TiramisuCmdlineParser(self.config,
|
||||||
|
self.prog,
|
||||||
|
fullpath=self.fullpath,
|
||||||
|
_forhelp=True)
|
||||||
|
return super(TiramisuCmdlineParser, help_formatter).format_usage(*args, **kwargs)
|
||||||
|
|
||||||
|
def format_help(self,
|
||||||
|
*args,
|
||||||
|
**kwargs):
|
||||||
|
help_formatter = TiramisuCmdlineParser(self.config,
|
||||||
|
self.prog,
|
||||||
|
fullpath=self.fullpath,
|
||||||
|
_forhelp=True)
|
||||||
|
return super(TiramisuCmdlineParser, help_formatter).format_help(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_config(self):
|
||||||
|
return self.config
|
||||||
Loading…
Reference in a new issue